diff --git a/CHANGELOG.md b/CHANGELOG.md index b02ad434482..e42f0eea459 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Added +- Add temporality selector functions `DeltaTemporalitySelector`, `CumulativeTemporalitySelector`, `LowMemoryTemporalitySelector` to `go.opentelemetry.io/otel/sdk/metric`. (#7434) - Add `WithInstrumentationAttributeSet` option to `go.opentelemetry.io/otel/log`, `go.opentelemetry.io/otel/metric`, and `go.opentelemetry.io/otel/trace` packages. This provides a concurrent-safe and performant alternative to `WithInstrumentationAttributes` by accepting a pre-constructed `attribute.Set`. (#7287) - Greatly reduce the cost of recording metrics in `go.opentelemetry.io/otel/sdk/metric` using hashing for map keys. (#7175) diff --git a/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/envconfig.go b/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/envconfig.go index b54a173b6ea..7f947273b5e 100644 --- a/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/envconfig.go +++ b/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/envconfig.go @@ -18,7 +18,6 @@ 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/metricdata" ) // DefaultEnvOptionsReader is the default environments reader. @@ -165,11 +164,11 @@ func withEnvTemporalityPreference(n string, fn func(metric.TemporalitySelector)) if s, ok := e.GetEnvValue(n); ok { switch strings.ToLower(s) { case "cumulative": - fn(cumulativeTemporality) + fn(metric.CumulativeTemporalitySelector) case "delta": - fn(deltaTemporality) + fn(metric.DeltaTemporalitySelector) case "lowmemory": - fn(lowMemory) + fn(metric.LowMemoryTemporalitySelector) default: global.Warn( "OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE is set to an invalid value, ignoring.", @@ -181,28 +180,6 @@ func withEnvTemporalityPreference(n string, fn func(metric.TemporalitySelector)) } } -func cumulativeTemporality(metric.InstrumentKind) metricdata.Temporality { - return metricdata.CumulativeTemporality -} - -func deltaTemporality(ik metric.InstrumentKind) metricdata.Temporality { - switch ik { - case metric.InstrumentKindCounter, metric.InstrumentKindHistogram, metric.InstrumentKindObservableCounter: - return metricdata.DeltaTemporality - default: - return metricdata.CumulativeTemporality - } -} - -func lowMemory(ik metric.InstrumentKind) metricdata.Temporality { - switch ik { - case metric.InstrumentKindCounter, metric.InstrumentKindHistogram: - return metricdata.DeltaTemporality - default: - 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 { diff --git a/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/envconfig.go b/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/envconfig.go index ef318ac676c..69224c97de8 100644 --- a/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/envconfig.go +++ b/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf/envconfig.go @@ -18,7 +18,6 @@ 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/metricdata" ) // DefaultEnvOptionsReader is the default environments reader. @@ -165,11 +164,11 @@ func withEnvTemporalityPreference(n string, fn func(metric.TemporalitySelector)) if s, ok := e.GetEnvValue(n); ok { switch strings.ToLower(s) { case "cumulative": - fn(cumulativeTemporality) + fn(metric.CumulativeTemporalitySelector) case "delta": - fn(deltaTemporality) + fn(metric.DeltaTemporalitySelector) case "lowmemory": - fn(lowMemory) + fn(metric.LowMemoryTemporalitySelector) default: global.Warn( "OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE is set to an invalid value, ignoring.", @@ -181,28 +180,6 @@ func withEnvTemporalityPreference(n string, fn func(metric.TemporalitySelector)) } } -func cumulativeTemporality(metric.InstrumentKind) metricdata.Temporality { - return metricdata.CumulativeTemporality -} - -func deltaTemporality(ik metric.InstrumentKind) metricdata.Temporality { - switch ik { - case metric.InstrumentKindCounter, metric.InstrumentKindHistogram, metric.InstrumentKindObservableCounter: - return metricdata.DeltaTemporality - default: - return metricdata.CumulativeTemporality - } -} - -func lowMemory(ik metric.InstrumentKind) metricdata.Temporality { - switch ik { - case metric.InstrumentKindCounter, metric.InstrumentKindHistogram: - return metricdata.DeltaTemporality - default: - 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 { diff --git a/internal/shared/otlp/otlpmetric/oconf/envconfig.go.tmpl b/internal/shared/otlp/otlpmetric/oconf/envconfig.go.tmpl index 3c864710351..67155dc6be6 100644 --- a/internal/shared/otlp/otlpmetric/oconf/envconfig.go.tmpl +++ b/internal/shared/otlp/otlpmetric/oconf/envconfig.go.tmpl @@ -18,7 +18,6 @@ import ( "{{ .envconfigImportPath }}" "go.opentelemetry.io/otel/internal/global" "go.opentelemetry.io/otel/sdk/metric" - "go.opentelemetry.io/otel/sdk/metric/metricdata" ) // DefaultEnvOptionsReader is the default environments reader. @@ -165,11 +164,11 @@ func withEnvTemporalityPreference(n string, fn func(metric.TemporalitySelector)) if s, ok := e.GetEnvValue(n); ok { switch strings.ToLower(s) { case "cumulative": - fn(cumulativeTemporality) + fn(metric.CumulativeTemporalitySelector) case "delta": - fn(deltaTemporality) + fn(metric.DeltaTemporalitySelector) case "lowmemory": - fn(lowMemory) + fn(metric.LowMemoryTemporalitySelector) default: global.Warn( "OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE is set to an invalid value, ignoring.", @@ -181,28 +180,6 @@ func withEnvTemporalityPreference(n string, fn func(metric.TemporalitySelector)) } } -func cumulativeTemporality(metric.InstrumentKind) metricdata.Temporality { - return metricdata.CumulativeTemporality -} - -func deltaTemporality(ik metric.InstrumentKind) metricdata.Temporality { - switch ik { - case metric.InstrumentKindCounter, metric.InstrumentKindHistogram, metric.InstrumentKindObservableCounter: - return metricdata.DeltaTemporality - default: - return metricdata.CumulativeTemporality - } -} - -func lowMemory(ik metric.InstrumentKind) metricdata.Temporality { - switch ik { - case metric.InstrumentKindCounter, metric.InstrumentKindHistogram: - return metricdata.DeltaTemporality - default: - 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 { diff --git a/sdk/metric/reader.go b/sdk/metric/reader.go index 5c1cea8254e..7b205c736c2 100644 --- a/sdk/metric/reader.go +++ b/sdk/metric/reader.go @@ -127,10 +127,40 @@ type TemporalitySelector func(InstrumentKind) metricdata.Temporality // DefaultTemporalitySelector is the default TemporalitySelector used if // WithTemporalitySelector is not provided. CumulativeTemporality will be used // for all instrument kinds if this TemporalitySelector is used. -func DefaultTemporalitySelector(InstrumentKind) metricdata.Temporality { +func DefaultTemporalitySelector(k InstrumentKind) metricdata.Temporality { + return CumulativeTemporalitySelector(k) +} + +// CumulativeTemporalitySelector is the TemporalitySelector that uses +// a cumulative temporality for all instrument kinds. +func CumulativeTemporalitySelector(InstrumentKind) metricdata.Temporality { return metricdata.CumulativeTemporality } +// DeltaTemporalitySelector is the TemporalitySelector that uses +// a delta temporality for instrument kinds: counter, histogram, observable counter +// All other instruments use cumulative temporality. +func DeltaTemporalitySelector(k InstrumentKind) metricdata.Temporality { + switch k { + case InstrumentKindCounter, InstrumentKindHistogram, InstrumentKindObservableCounter: + return metricdata.DeltaTemporality + default: + return metricdata.CumulativeTemporality + } +} + +// LowMemoryTemporalitySelector is the TemporalitySelector that uses +// delta temporality for counters and histograms. All other instruments use +// cumulative temporality. +func LowMemoryTemporalitySelector(k InstrumentKind) metricdata.Temporality { + switch k { + case InstrumentKindCounter, InstrumentKindHistogram: + return metricdata.DeltaTemporality + default: + return metricdata.CumulativeTemporality + } +} + // AggregationSelector selects the aggregation and the parameters to use for // that aggregation based on the InstrumentKind. // diff --git a/sdk/metric/reader_test.go b/sdk/metric/reader_test.go index b8c5a8a8d7f..eee7d6c4736 100644 --- a/sdk/metric/reader_test.go +++ b/sdk/metric/reader_test.go @@ -333,6 +333,64 @@ func TestDefaultTemporalitySelector(t *testing.T) { } } +func TestCumulativeTemporalitySelector(t *testing.T) { + var undefinedInstrument InstrumentKind + for _, ik := range []InstrumentKind{ + undefinedInstrument, + InstrumentKindCounter, + InstrumentKindUpDownCounter, + InstrumentKindHistogram, + InstrumentKindGauge, + InstrumentKindObservableCounter, + InstrumentKindObservableUpDownCounter, + InstrumentKindObservableGauge, + } { + assert.Equal(t, metricdata.CumulativeTemporality, CumulativeTemporalitySelector(ik)) + } +} + +func TestDeltaTemporalitySelector(t *testing.T) { + var undefinedInstrument InstrumentKind + for _, ik := range []InstrumentKind{ + InstrumentKindCounter, + InstrumentKindHistogram, + InstrumentKindObservableCounter, + } { + assert.Equal(t, metricdata.DeltaTemporality, DeltaTemporalitySelector(ik)) + } + + for _, ik := range []InstrumentKind{ + undefinedInstrument, + InstrumentKindGauge, + InstrumentKindObservableGauge, + InstrumentKindObservableUpDownCounter, + InstrumentKindUpDownCounter, + } { + assert.Equal(t, metricdata.CumulativeTemporality, DeltaTemporalitySelector(ik)) + } +} + +func TestLowMemoryTemporalitySelector(t *testing.T) { + var undefinedInstrument InstrumentKind + for _, ik := range []InstrumentKind{ + InstrumentKindCounter, + InstrumentKindHistogram, + } { + assert.Equal(t, metricdata.DeltaTemporality, LowMemoryTemporalitySelector(ik)) + } + + for _, ik := range []InstrumentKind{ + undefinedInstrument, + InstrumentKindGauge, + InstrumentKindObservableCounter, + InstrumentKindObservableGauge, + InstrumentKindObservableUpDownCounter, + InstrumentKindUpDownCounter, + } { + assert.Equal(t, metricdata.CumulativeTemporality, LowMemoryTemporalitySelector(ik)) + } +} + type notComparable [0]func() // nolint:unused // non-comparable type itself is used. type noCompareReader struct {