Skip to content

Commit

Permalink
[exporter/datadog] Add metrics::sums::cumulative_monotonic_mode set…
Browse files Browse the repository at this point in the history
…ting; deprecate `metrics::send_monotonic_counter` (#8490)

* [exporter/datadog] Add `metrics::sums::cumulative_monotonic_mode` setting; deprecate `metrics::send_monotonic_counter`

* Add CHANGELOG entries for this change

* [exporter/datadog] Update documentation

* [exporter/datadog] Add unit tests for renaming error

* Fix formatting

* [exporter/datadog] Minor copyedit on error message

* [exporter/datadog] Fix comment

* Address review comments
  • Loading branch information
mx-psi authored Mar 25, 2022
1 parent e1bfb60 commit c2e9a91
Show file tree
Hide file tree
Showing 11 changed files with 315 additions and 3 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@
- `cmd/mdatagen`: Add resource attributes definition to metadata.yaml and move `pdata.Metrics` creation to the
generated code (#5270)

### 💡 Enhancements 💡

- `datadogexporter`: Add `metrics::sums::cumulative_monotonic_mode` to specify export mode for cumulative monotonic sums (#8490)

### 🚩 Deprecations 🚩

- `datadogexporter`: Deprecate `metrics::send_monotonic_counter` in favor of `metrics::sums::cumulative_monotonic_mode` (#8490)

## v0.47.0

### 💡 Enhancements 💡
Expand Down
52 changes: 52 additions & 0 deletions exporter/datadogexporter/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package config // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/config"

import (
"encoding"
"errors"
"fmt"
"regexp"
Expand Down Expand Up @@ -77,6 +78,7 @@ type MetricsConfig struct {

// SendMonotonic states whether to report cumulative monotonic metrics as counters
// or gauges
// Deprecated: [v0.48.0] Use `metrics::sums::cumulative_monotonic_mode` (SumConfig.CumulativeMonotonicMode) instead.
SendMonotonic bool `mapstructure:"send_monotonic_counter"`

// DeltaTTL defines the time that previous points of a cumulative monotonic
Expand All @@ -92,6 +94,9 @@ type MetricsConfig struct {

// HistConfig defines the export of OTLP Histograms.
HistConfig HistogramConfig `mapstructure:"histograms"`

// SumConfig defines the export of OTLP Sums.
SumConfig SumConfig `mapstructure:"sums"`
}

// HistogramConfig customizes export of OTLP Histograms.
Expand All @@ -117,6 +122,46 @@ func (c *HistogramConfig) validate() error {
return nil
}

// CumulativeMonotonicSumMode is the export mode for OTLP Sum metrics.
type CumulativeMonotonicSumMode string

const (
// CumulativeMonotonicSumModeToDelta calculates delta for
// cumulative monotonic sum metrics in the client side and reports
// them as Datadog counts.
CumulativeMonotonicSumModeToDelta CumulativeMonotonicSumMode = "to_delta"

// CumulativeMonotonicSumModeRawValue reports the raw value for
// cumulative monotonic sum metrics as a Datadog gauge.
CumulativeMonotonicSumModeRawValue CumulativeMonotonicSumMode = "raw_value"
)

var _ encoding.TextUnmarshaler = (*CumulativeMonotonicSumMode)(nil)

// UnmarshalText implements the encoding.TextUnmarshaler interface.
func (sm *CumulativeMonotonicSumMode) UnmarshalText(in []byte) error {
switch mode := CumulativeMonotonicSumMode(in); mode {
case CumulativeMonotonicSumModeToDelta,
CumulativeMonotonicSumModeRawValue:
*sm = mode
return nil
default:
return fmt.Errorf("invalid cumulative monotonic sum mode %q", mode)
}
}

// SumConfig customizes export of OTLP Sums.
type SumConfig struct {
// CumulativeMonotonicMode is the mode for exporting OTLP Cumulative Monotonic Sums.
// Valid values are 'to_delta' or 'raw_value'.
// - 'to_delta' calculates delta for cumulative monotonic sums and sends it as a Datadog count.
// - 'raw_value' sends the raw value of cumulative monotonic sums as Datadog gauges.
//
// The default is 'to_delta'.
// See https://docs.datadoghq.com/metrics/otlp/?tab=sum#mapping for details and examples.
CumulativeMonotonicMode CumulativeMonotonicSumMode `mapstructure:"cumulative_monotonic_mode"`
}

// MetricsExporterConfig provides options for a user to customize the behavior of the
// metrics exporter
type MetricsExporterConfig struct {
Expand Down Expand Up @@ -352,6 +397,13 @@ func (c *Config) Unmarshal(configMap *config.Map) error {
return err
}

// Add deprecation warnings for deprecated settings.
renamingWarnings, err := handleRenamedSettings(configMap, c)
if err != nil {
return err
}
c.warnings = append(c.warnings, renamingWarnings...)

switch c.Metrics.HistConfig.Mode {
case histogramModeCounters, histogramModeNoBuckets, histogramModeDistributions:
// Do nothing
Expand Down
15 changes: 15 additions & 0 deletions exporter/datadogexporter/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/config"
"go.opentelemetry.io/collector/config/confignet"
"go.uber.org/zap"
)
Expand Down Expand Up @@ -190,3 +191,17 @@ func TestSpanNameRemappingsValidation(t *testing.T) {
require.NoError(t, noErr)
require.Error(t, err)
}

func TestInvalidSumMode(t *testing.T) {
cfgMap := config.NewMapFromStringMap(map[string]interface{}{
"metrics": map[string]interface{}{
"sums": map[string]interface{}{
"cumulative_monotonic_mode": "invalid_mode",
},
},
})

cfg := futureDefaultConfig()
err := cfg.Unmarshal(cfgMap)
assert.EqualError(t, err, "1 error(s) decoding:\n\n* error decoding 'metrics.sums.cumulative_monotonic_mode': invalid cumulative monotonic sum mode \"invalid_mode\"")
}
3 changes: 3 additions & 0 deletions exporter/datadogexporter/config/warn_envvars.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ func futureDefaultConfig() *Config {
Mode: "distributions",
SendCountSum: false,
},
SumConfig: SumConfig{
CumulativeMonotonicMode: CumulativeMonotonicSumModeToDelta,
},
},
Traces: TracesConfig{
SampleRate: 1,
Expand Down
97 changes: 97 additions & 0 deletions exporter/datadogexporter/config/warning_deprecated.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/config"

import (
"fmt"

"go.opentelemetry.io/collector/config"
"go.uber.org/multierr"
)

var _ error = (*renameError)(nil)

// renameError is an error related to a renamed setting.
type renameError struct {
// oldName of the configuration option.
oldName string
// newName of the configuration option.
newName string
// oldRemovedIn is the version where the old config option will be removed.
oldRemovedIn string
// updateFn updates the configuration to map the old value into the new one.
// It must only be called when the old value is set and is not the default.
updateFn func(*Config)
// issueNumber on opentelemetry-collector-contrib for tracking
issueNumber uint
}

// List of settings that are deprecated.
var renamedSettings = []renameError{
{
oldName: "metrics::send_monotonic_counter",
newName: "metrics::sums::cumulative_monotonic_mode",
oldRemovedIn: "v0.50.0",
issueNumber: 8489,
updateFn: func(c *Config) {
if c.Metrics.SendMonotonic {
c.Metrics.SumConfig.CumulativeMonotonicMode = CumulativeMonotonicSumModeToDelta
} else {
c.Metrics.SumConfig.CumulativeMonotonicMode = CumulativeMonotonicSumModeRawValue
}
},
},
}

// Error implements the error interface.
func (e renameError) Error() string {
return fmt.Sprintf(
"%q has been deprecated in favor of %q and will be removed in %s. See github.com/open-telemetry/opentelemetry-collector-contrib/issues/%d",
e.oldName,
e.newName,
e.oldRemovedIn,
e.issueNumber,
)
}

// Check if the deprecated option is being used.
// Error out if both the old and new options are being used.
func (e renameError) Check(configMap *config.Map) (bool, error) {
if configMap.IsSet(e.oldName) && configMap.IsSet(e.newName) {
return false, fmt.Errorf("%q and %q can't be both set at the same time: use %q only instead", e.oldName, e.newName, e.newName)
}
return configMap.IsSet(e.oldName), nil
}

// UpdateCfg to move the old configuration value into the new one.
func (e renameError) UpdateCfg(cfg *Config) {
e.updateFn(cfg)
}

// handleRenamedSettings for a given configuration map.
// Error out if any pair of old-new options are set at the same time.
func handleRenamedSettings(configMap *config.Map, cfg *Config) (warnings []error, err error) {
for _, renaming := range renamedSettings {
isOldNameUsed, errCheck := renaming.Check(configMap)
err = multierr.Append(err, errCheck)

if errCheck == nil && isOldNameUsed {
warnings = append(warnings, renaming)
// only update config if old name is in use
renaming.UpdateCfg(cfg)
}
}
return
}
103 changes: 103 additions & 0 deletions exporter/datadogexporter/config/warning_deprecated_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/config"

import (
"testing"

"github.com/stretchr/testify/assert"
"go.opentelemetry.io/collector/config"
)

func TestDeprecationSendMonotonic(t *testing.T) {
tests := []struct {
name string
cfgMap *config.Map
expectedMode CumulativeMonotonicSumMode
warnings []string
err string
}{
{
name: "both metrics::send_monotonic and new metrics::sums::cumulative_monotonic_mode",
cfgMap: config.NewMapFromStringMap(map[string]interface{}{
"metrics": map[string]interface{}{
"send_monotonic_counter": true,
"sums": map[string]interface{}{
"cumulative_monotonic_mode": "to_delta",
},
},
}),
err: "\"metrics::send_monotonic_counter\" and \"metrics::sums::cumulative_monotonic_mode\" can't be both set at the same time: use \"metrics::sums::cumulative_monotonic_mode\" only instead",
},
{
name: "metrics::send_monotonic set to true",
cfgMap: config.NewMapFromStringMap(map[string]interface{}{
"metrics": map[string]interface{}{
"send_monotonic_counter": true,
},
}),
expectedMode: CumulativeMonotonicSumModeToDelta,
warnings: []string{
"\"metrics::send_monotonic_counter\" has been deprecated in favor of \"metrics::sums::cumulative_monotonic_mode\" and will be removed in v0.50.0. See github.com/open-telemetry/opentelemetry-collector-contrib/issues/8489",
},
},
{
name: "metrics::send_monotonic set to false",
cfgMap: config.NewMapFromStringMap(map[string]interface{}{
"metrics": map[string]interface{}{
"send_monotonic_counter": false,
},
}),
expectedMode: CumulativeMonotonicSumModeRawValue,
warnings: []string{
"\"metrics::send_monotonic_counter\" has been deprecated in favor of \"metrics::sums::cumulative_monotonic_mode\" and will be removed in v0.50.0. See github.com/open-telemetry/opentelemetry-collector-contrib/issues/8489",
},
},
{
name: "metrics::send_monotonic and metrics::sums::cumulative_monotonic_mode unset",
cfgMap: config.NewMapFromStringMap(map[string]interface{}{}),
expectedMode: CumulativeMonotonicSumModeToDelta,
},
{
name: "metrics::sums::cumulative_monotonic_mode set",
cfgMap: config.NewMapFromStringMap(map[string]interface{}{
"metrics": map[string]interface{}{
"sums": map[string]interface{}{
"cumulative_monotonic_mode": "raw_value",
},
},
}),
expectedMode: CumulativeMonotonicSumModeRawValue,
},
}

for _, testInstance := range tests {
t.Run(testInstance.name, func(t *testing.T) {
cfg := futureDefaultConfig()
err := cfg.Unmarshal(testInstance.cfgMap)
if err != nil || testInstance.err != "" {
assert.EqualError(t, err, testInstance.err)
} else {
assert.Equal(t, testInstance.expectedMode, cfg.Metrics.SumConfig.CumulativeMonotonicMode)
var warningStr []string
for _, warning := range cfg.warnings {
warningStr = append(warningStr, warning.Error())
}
assert.ElementsMatch(t, testInstance.warnings, warningStr)
}
})
}

}
11 changes: 11 additions & 0 deletions exporter/datadogexporter/example/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ exporters:
#
# metrics:
## @param send_monotonic_counter - boolean - optional - default: true
## Deprecated: [v0.48.0] Use `metrics::sums::cumulative_monotonic_mode` instead.
## Whether to report monotonic metrics as counters or gauges (raw value).
## See https://docs.datadoghq.com/integrations/guide/prometheus-metrics/#counter
## for further details
Expand Down Expand Up @@ -118,6 +119,16 @@ exporters:
## Whether to report sum and count as separate histogram metrics.
#
# send_count_sum_metrics: false

## @param sums - custom object - optional
## Sums specific configuration.
## @param cumulative_monotonic_mode - string - optional - default: to_delta
## How to report cumulative monotonic sums. Valid values are:
##
## - `to_delta` to calculate delta for sum in the client side and report as Datadog counts.
## - `raw_value` to report the raw value as a Datadog gauge.
#
# cumulative_monotonic_mode: to_delta

## @param traces - custom object - optional
## Trace exporter specific configuration.
Expand Down
3 changes: 3 additions & 0 deletions exporter/datadogexporter/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ func (*factory) createDefaultConfig() config.Exporter {
Mode: "distributions",
SendCountSum: false,
},
SumConfig: ddconfig.SumConfig{
CumulativeMonotonicMode: ddconfig.CumulativeMonotonicSumModeToDelta,
},
},

Traces: ddconfig.TracesConfig{
Expand Down
Loading

0 comments on commit c2e9a91

Please sign in to comment.