Skip to content

Commit

Permalink
Support default histogram selection in OTLP exporter (#4437)
Browse files Browse the repository at this point in the history
* Support default histogram selection in OTLP exporter

* Add changes to changelog
  • Loading branch information
MrAlias committed Aug 14, 2023
1 parent af1d928 commit 199dc34
Show file tree
Hide file tree
Showing 7 changed files with 292 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Accept 201 to 299 HTTP status as success in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` and `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#4365)
- Document the `Temporality` and `Aggregation` methods of the `"go.opentelemetry.io/otel/sdk/metric".Exporter"` need to be concurrent safe. (#4381)
- Expand the set of units supported by the prometheus exporter, and don't add unit suffixes if they are already present in `go.opentelemetry.op/otel/exporters/prometheus` (#4374)
- The exporters in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` support the `OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION` environment variable. (#4437)

### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/envconfig"
"go.opentelemetry.io/otel/internal/global"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/aggregation"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
)

Expand Down Expand Up @@ -103,6 +104,7 @@ func getOptionsFromEnv() []GenericOption {
envconfig.WithDuration("TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }),
envconfig.WithDuration("METRICS_TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }),
withEnvTemporalityPreference("METRICS_TEMPORALITY_PREFERENCE", func(t metric.TemporalitySelector) { opts = append(opts, WithTemporalitySelector(t)) }),
withEnvAggPreference("METRICS_DEFAULT_HISTOGRAM_AGGREGATION", func(a metric.AggregationSelector) { opts = append(opts, WithAggregationSelector(a)) }),
)

return opts
Expand Down Expand Up @@ -194,3 +196,27 @@ func lowMemory(ik metric.InstrumentKind) metricdata.Temporality {
return metricdata.CumulativeTemporality
}
}

func withEnvAggPreference(n string, fn func(metric.AggregationSelector)) func(e *envconfig.EnvOptionsReader) {
return func(e *envconfig.EnvOptionsReader) {
if s, ok := e.GetEnvValue(n); ok {
switch strings.ToLower(s) {
case "explicit_bucket_histogram":
fn(metric.DefaultAggregationSelector)
case "base2_exponential_bucket_histogram":
fn(func(kind metric.InstrumentKind) aggregation.Aggregation {
if kind == metric.InstrumentKindHistogram {
return aggregation.Base2ExponentialHistogram{
MaxSize: 160,
MaxScale: 20,
NoMinMax: false,
}
}
return metric.DefaultAggregationSelector(kind)
})
default:
global.Warn("OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION is set to an invalid value, ignoring.", "value", s)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/stretchr/testify/require"

"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/aggregation"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
)

Expand Down Expand Up @@ -104,3 +105,73 @@ func TestWithEnvTemporalityPreference(t *testing.T) {
}
DefaultEnvOptionsReader.GetEnv = origReader
}

func TestWithEnvAggPreference(t *testing.T) {
origReader := DefaultEnvOptionsReader.GetEnv
tests := []struct {
name string
envValue string
want map[metric.InstrumentKind]aggregation.Aggregation
}{
{
name: "default do not set the selector",
envValue: "",
},
{
name: "non-normative do not set the selector",
envValue: "non-normative",
},
{
name: "explicit_bucket_histogram",
envValue: "explicit_bucket_histogram",
want: map[metric.InstrumentKind]aggregation.Aggregation{
metric.InstrumentKindCounter: metric.DefaultAggregationSelector(metric.InstrumentKindCounter),
metric.InstrumentKindHistogram: metric.DefaultAggregationSelector(metric.InstrumentKindHistogram),
metric.InstrumentKindUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindUpDownCounter),
metric.InstrumentKindObservableCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableCounter),
metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableUpDownCounter),
metric.InstrumentKindObservableGauge: metric.DefaultAggregationSelector(metric.InstrumentKindObservableGauge),
},
},
{
name: "base2_exponential_bucket_histogram",
envValue: "base2_exponential_bucket_histogram",
want: map[metric.InstrumentKind]aggregation.Aggregation{
metric.InstrumentKindCounter: metric.DefaultAggregationSelector(metric.InstrumentKindCounter),
metric.InstrumentKindHistogram: aggregation.Base2ExponentialHistogram{
MaxSize: 160,
MaxScale: 20,
NoMinMax: false,
},
metric.InstrumentKindUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindUpDownCounter),
metric.InstrumentKindObservableCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableCounter),
metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableUpDownCounter),
metric.InstrumentKindObservableGauge: metric.DefaultAggregationSelector(metric.InstrumentKindObservableGauge),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
DefaultEnvOptionsReader.GetEnv = func(key string) string {
if key == "OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION" {
return tt.envValue
}
return origReader(key)
}
cfg := Config{}
cfg = ApplyGRPCEnvConfigs(cfg)

if tt.want == nil {
// There is no function set, the SDK's default is used.
assert.Nil(t, cfg.Metrics.AggregationSelector)
return
}

require.NotNil(t, cfg.Metrics.AggregationSelector)
for ik, want := range tt.want {
assert.Equal(t, want, cfg.Metrics.AggregationSelector(ik))
}
})
}
DefaultEnvOptionsReader.GetEnv = origReader
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/envconfig"
"go.opentelemetry.io/otel/internal/global"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/aggregation"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
)

Expand Down Expand Up @@ -103,6 +104,7 @@ func getOptionsFromEnv() []GenericOption {
envconfig.WithDuration("TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }),
envconfig.WithDuration("METRICS_TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }),
withEnvTemporalityPreference("METRICS_TEMPORALITY_PREFERENCE", func(t metric.TemporalitySelector) { opts = append(opts, WithTemporalitySelector(t)) }),
withEnvAggPreference("METRICS_DEFAULT_HISTOGRAM_AGGREGATION", func(a metric.AggregationSelector) { opts = append(opts, WithAggregationSelector(a)) }),
)

return opts
Expand Down Expand Up @@ -194,3 +196,27 @@ func lowMemory(ik metric.InstrumentKind) metricdata.Temporality {
return metricdata.CumulativeTemporality
}
}

func withEnvAggPreference(n string, fn func(metric.AggregationSelector)) func(e *envconfig.EnvOptionsReader) {
return func(e *envconfig.EnvOptionsReader) {
if s, ok := e.GetEnvValue(n); ok {
switch strings.ToLower(s) {
case "explicit_bucket_histogram":
fn(metric.DefaultAggregationSelector)
case "base2_exponential_bucket_histogram":
fn(func(kind metric.InstrumentKind) aggregation.Aggregation {
if kind == metric.InstrumentKindHistogram {
return aggregation.Base2ExponentialHistogram{
MaxSize: 160,
MaxScale: 20,
NoMinMax: false,
}
}
return metric.DefaultAggregationSelector(kind)
})
default:
global.Warn("OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION is set to an invalid value, ignoring.", "value", s)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/stretchr/testify/require"

"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/aggregation"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
)

Expand Down Expand Up @@ -104,3 +105,73 @@ func TestWithEnvTemporalityPreference(t *testing.T) {
}
DefaultEnvOptionsReader.GetEnv = origReader
}

func TestWithEnvAggPreference(t *testing.T) {
origReader := DefaultEnvOptionsReader.GetEnv
tests := []struct {
name string
envValue string
want map[metric.InstrumentKind]aggregation.Aggregation
}{
{
name: "default do not set the selector",
envValue: "",
},
{
name: "non-normative do not set the selector",
envValue: "non-normative",
},
{
name: "explicit_bucket_histogram",
envValue: "explicit_bucket_histogram",
want: map[metric.InstrumentKind]aggregation.Aggregation{
metric.InstrumentKindCounter: metric.DefaultAggregationSelector(metric.InstrumentKindCounter),
metric.InstrumentKindHistogram: metric.DefaultAggregationSelector(metric.InstrumentKindHistogram),
metric.InstrumentKindUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindUpDownCounter),
metric.InstrumentKindObservableCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableCounter),
metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableUpDownCounter),
metric.InstrumentKindObservableGauge: metric.DefaultAggregationSelector(metric.InstrumentKindObservableGauge),
},
},
{
name: "base2_exponential_bucket_histogram",
envValue: "base2_exponential_bucket_histogram",
want: map[metric.InstrumentKind]aggregation.Aggregation{
metric.InstrumentKindCounter: metric.DefaultAggregationSelector(metric.InstrumentKindCounter),
metric.InstrumentKindHistogram: aggregation.Base2ExponentialHistogram{
MaxSize: 160,
MaxScale: 20,
NoMinMax: false,
},
metric.InstrumentKindUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindUpDownCounter),
metric.InstrumentKindObservableCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableCounter),
metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableUpDownCounter),
metric.InstrumentKindObservableGauge: metric.DefaultAggregationSelector(metric.InstrumentKindObservableGauge),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
DefaultEnvOptionsReader.GetEnv = func(key string) string {
if key == "OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION" {
return tt.envValue
}
return origReader(key)
}
cfg := Config{}
cfg = ApplyGRPCEnvConfigs(cfg)

if tt.want == nil {
// There is no function set, the SDK's default is used.
assert.Nil(t, cfg.Metrics.AggregationSelector)
return
}

require.NotNil(t, cfg.Metrics.AggregationSelector)
for ik, want := range tt.want {
assert.Equal(t, want, cfg.Metrics.AggregationSelector(ik))
}
})
}
DefaultEnvOptionsReader.GetEnv = origReader
}
26 changes: 26 additions & 0 deletions internal/shared/otlp/otlpmetric/oconf/envconfig.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"{{ .envconfigImportPath }}"
"go.opentelemetry.io/otel/internal/global"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/aggregation"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
)

Expand Down Expand Up @@ -103,6 +104,7 @@ func getOptionsFromEnv() []GenericOption {
envconfig.WithDuration("TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }),
envconfig.WithDuration("METRICS_TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }),
withEnvTemporalityPreference("METRICS_TEMPORALITY_PREFERENCE", func(t metric.TemporalitySelector) { opts = append(opts, WithTemporalitySelector(t)) }),
withEnvAggPreference("METRICS_DEFAULT_HISTOGRAM_AGGREGATION", func(a metric.AggregationSelector) { opts = append(opts, WithAggregationSelector(a)) }),
)

return opts
Expand Down Expand Up @@ -194,3 +196,27 @@ func lowMemory(ik metric.InstrumentKind) metricdata.Temporality {
return metricdata.CumulativeTemporality
}
}

func withEnvAggPreference(n string, fn func(metric.AggregationSelector)) func(e *envconfig.EnvOptionsReader) {
return func(e *envconfig.EnvOptionsReader) {
if s, ok := e.GetEnvValue(n); ok {
switch strings.ToLower(s) {
case "explicit_bucket_histogram":
fn(metric.DefaultAggregationSelector)
case "base2_exponential_bucket_histogram":
fn(func(kind metric.InstrumentKind) aggregation.Aggregation {
if kind == metric.InstrumentKindHistogram {
return aggregation.Base2ExponentialHistogram{
MaxSize: 160,
MaxScale: 20,
NoMinMax: false,
}
}
return metric.DefaultAggregationSelector(kind)
})
default:
global.Warn("OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION is set to an invalid value, ignoring.", "value", s)
}
}
}
}
71 changes: 71 additions & 0 deletions internal/shared/otlp/otlpmetric/oconf/envconfig_test.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/stretchr/testify/require"

"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/aggregation"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
)

Expand Down Expand Up @@ -104,3 +105,73 @@ func TestWithEnvTemporalityPreference(t *testing.T) {
}
DefaultEnvOptionsReader.GetEnv = origReader
}

func TestWithEnvAggPreference(t *testing.T) {
origReader := DefaultEnvOptionsReader.GetEnv
tests := []struct {
name string
envValue string
want map[metric.InstrumentKind]aggregation.Aggregation
}{
{
name: "default do not set the selector",
envValue: "",
},
{
name: "non-normative do not set the selector",
envValue: "non-normative",
},
{
name: "explicit_bucket_histogram",
envValue: "explicit_bucket_histogram",
want: map[metric.InstrumentKind]aggregation.Aggregation{
metric.InstrumentKindCounter: metric.DefaultAggregationSelector(metric.InstrumentKindCounter),
metric.InstrumentKindHistogram: metric.DefaultAggregationSelector(metric.InstrumentKindHistogram),
metric.InstrumentKindUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindUpDownCounter),
metric.InstrumentKindObservableCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableCounter),
metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableUpDownCounter),
metric.InstrumentKindObservableGauge: metric.DefaultAggregationSelector(metric.InstrumentKindObservableGauge),
},
},
{
name: "base2_exponential_bucket_histogram",
envValue: "base2_exponential_bucket_histogram",
want: map[metric.InstrumentKind]aggregation.Aggregation{
metric.InstrumentKindCounter: metric.DefaultAggregationSelector(metric.InstrumentKindCounter),
metric.InstrumentKindHistogram: aggregation.Base2ExponentialHistogram{
MaxSize: 160,
MaxScale: 20,
NoMinMax: false,
},
metric.InstrumentKindUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindUpDownCounter),
metric.InstrumentKindObservableCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableCounter),
metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableUpDownCounter),
metric.InstrumentKindObservableGauge: metric.DefaultAggregationSelector(metric.InstrumentKindObservableGauge),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
DefaultEnvOptionsReader.GetEnv = func(key string) string {
if key == "OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION" {
return tt.envValue
}
return origReader(key)
}
cfg := Config{}
cfg = ApplyGRPCEnvConfigs(cfg)

if tt.want == nil {
// There is no function set, the SDK's default is used.
assert.Nil(t, cfg.Metrics.AggregationSelector)
return
}

require.NotNil(t, cfg.Metrics.AggregationSelector)
for ik, want := range tt.want {
assert.Equal(t, want, cfg.Metrics.AggregationSelector(ik))
}
})
}
DefaultEnvOptionsReader.GetEnv = origReader
}

0 comments on commit 199dc34

Please sign in to comment.