1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-10-31 00:07:40 +02:00

Add temporality selector functions (#7434)

From: https://github.com/open-telemetry/opentelemetry-go/pull/7346

This PR exposes the default TemporalitySelector funcs that are used by
the OTel env var processing.

The reason to expose these funcs is because there is some discrepancy in
various vendor documentation on how to enable these settings using go
option args WithTemporalitySelector

https://cloud-native.slack.com/archives/C01NPAXACKT/p1757443233624599

---------

Co-authored-by: Damien Mathieu <42@dmathieu.com>
Co-authored-by: David Ashpole <dashpole@google.com>
This commit is contained in:
Dave Protasowski
2025-10-02 10:13:59 -04:00
committed by GitHub
parent ffeeee82a8
commit dee11e6ae3
6 changed files with 99 additions and 79 deletions

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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.
//

View File

@@ -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 {