Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[exporter/datadog] Add metrics::sums::cumulative_monotonic_mode setting; deprecate metrics::send_monotonic_counter #8490

Merged
merged 8 commits into from
Mar 25, 2022
Merged
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

## Unreleased

### 💡 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 @@ -76,6 +77,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 @@ -91,6 +93,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 @@ -116,6 +121,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 @@ -348,6 +393,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.
mx-psi marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -89,6 +89,9 @@ func createDefaultConfig() config.Exporter {
Mode: "distributions",
SendCountSum: false,
},
SumConfig: ddconfig.SumConfig{
CumulativeMonotonicMode: ddconfig.CumulativeMonotonicSumModeToDelta,
},
},

Traces: ddconfig.TracesConfig{
Expand Down
Loading