From 0bbcbc429ce868b702ebe03bd3400bd748ecb8a8 Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Thu, 4 Jul 2024 14:16:22 -0700 Subject: [PATCH 1/2] config: add support for temporality configuration This adds functionality to set temporality preferences for exporters in the configuration of metric exporters. Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- config/metric.go | 47 ++++++++++++ config/metric_test.go | 162 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 208 insertions(+), 1 deletion(-) diff --git a/config/metric.go b/config/metric.go index 72f21cf3850..dab2cfc9ff0 100644 --- a/config/metric.go +++ b/config/metric.go @@ -27,6 +27,7 @@ import ( "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/sdk/instrumentation" sdkmetric "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/resource" ) @@ -166,6 +167,18 @@ func otlpHTTPMetricExporter(ctx context.Context, otlpConfig *OTLPMetric) (sdkmet if len(otlpConfig.Headers) > 0 { opts = append(opts, otlpmetrichttp.WithHeaders(otlpConfig.Headers)) } + if otlpConfig.TemporalityPreference != nil { + switch *otlpConfig.TemporalityPreference { + case "delta": + opts = append(opts, otlpmetrichttp.WithTemporalitySelector(deltaTemporality)) + case "cumulative": + opts = append(opts, otlpmetrichttp.WithTemporalitySelector(cumulativeTemporality)) + case "lowmemory": + opts = append(opts, otlpmetrichttp.WithTemporalitySelector(lowMemory)) + default: + return nil, fmt.Errorf("unsupported temporality preference %q", *otlpConfig.TemporalityPreference) + } + } return otlpmetrichttp.New(ctx, opts...) } @@ -209,10 +222,44 @@ func otlpGRPCMetricExporter(ctx context.Context, otlpConfig *OTLPMetric) (sdkmet if len(otlpConfig.Headers) > 0 { opts = append(opts, otlpmetricgrpc.WithHeaders(otlpConfig.Headers)) } + if otlpConfig.TemporalityPreference != nil { + switch *otlpConfig.TemporalityPreference { + case "delta": + opts = append(opts, otlpmetricgrpc.WithTemporalitySelector(deltaTemporality)) + case "cumulative": + opts = append(opts, otlpmetricgrpc.WithTemporalitySelector(cumulativeTemporality)) + case "lowmemory": + opts = append(opts, otlpmetricgrpc.WithTemporalitySelector(lowMemory)) + default: + return nil, fmt.Errorf("unsupported temporality preference %q", *otlpConfig.TemporalityPreference) + } + } return otlpmetricgrpc.New(ctx, opts...) } +func cumulativeTemporality(sdkmetric.InstrumentKind) metricdata.Temporality { + return metricdata.CumulativeTemporality +} + +func deltaTemporality(ik sdkmetric.InstrumentKind) metricdata.Temporality { + switch ik { + case sdkmetric.InstrumentKindCounter, sdkmetric.InstrumentKindHistogram, sdkmetric.InstrumentKindObservableCounter: + return metricdata.DeltaTemporality + default: + return metricdata.CumulativeTemporality + } +} + +func lowMemory(ik sdkmetric.InstrumentKind) metricdata.Temporality { + switch ik { + case sdkmetric.InstrumentKindCounter, sdkmetric.InstrumentKindHistogram: + return metricdata.DeltaTemporality + default: + return metricdata.CumulativeTemporality + } +} + func prometheusReader(ctx context.Context, prometheusConfig *Prometheus) (sdkmetric.Reader, error) { var opts []otelprom.Option if prometheusConfig.Host == nil { diff --git a/config/metric_test.go b/config/metric_test.go index 83aa7a8beb0..4df5209d7fc 100644 --- a/config/metric_test.go +++ b/config/metric_test.go @@ -264,7 +264,7 @@ func TestReader(t *testing.T) { wantErr: &url.Error{Op: "parse", URL: " ", Err: errors.New("invalid URI for request")}, }, { - name: "periodic/grpc-http-none-compression", + name: "periodic/otlp-grpc-none-compression", reader: MetricReader{ Periodic: &PeriodicMetricReader{ Exporter: MetricExporter{ @@ -282,6 +282,86 @@ func TestReader(t *testing.T) { }, wantReader: sdkmetric.NewPeriodicReader(otlpGRPCExporter), }, + { + name: "periodic/otlp-grpc-delta-temporality", + reader: MetricReader{ + Periodic: &PeriodicMetricReader{ + Exporter: MetricExporter{ + OTLP: &OTLPMetric{ + Protocol: "grpc/protobuf", + Endpoint: "localhost:4318", + Compression: ptr("none"), + Timeout: ptr(1000), + Headers: map[string]string{ + "test": "test1", + }, + TemporalityPreference: ptr("delta"), + }, + }, + }, + }, + wantReader: sdkmetric.NewPeriodicReader(otlpGRPCExporter), + }, + { + name: "periodic/otlp-grpc-cumulative-temporality", + reader: MetricReader{ + Periodic: &PeriodicMetricReader{ + Exporter: MetricExporter{ + OTLP: &OTLPMetric{ + Protocol: "grpc/protobuf", + Endpoint: "localhost:4318", + Compression: ptr("none"), + Timeout: ptr(1000), + Headers: map[string]string{ + "test": "test1", + }, + TemporalityPreference: ptr("cumulative"), + }, + }, + }, + }, + wantReader: sdkmetric.NewPeriodicReader(otlpGRPCExporter), + }, + { + name: "periodic/otlp-grpc-lowmemory-temporality", + reader: MetricReader{ + Periodic: &PeriodicMetricReader{ + Exporter: MetricExporter{ + OTLP: &OTLPMetric{ + Protocol: "grpc/protobuf", + Endpoint: "localhost:4318", + Compression: ptr("none"), + Timeout: ptr(1000), + Headers: map[string]string{ + "test": "test1", + }, + TemporalityPreference: ptr("lowmemory"), + }, + }, + }, + }, + wantReader: sdkmetric.NewPeriodicReader(otlpGRPCExporter), + }, + { + name: "periodic/otlp-grpc-invalid-temporality", + reader: MetricReader{ + Periodic: &PeriodicMetricReader{ + Exporter: MetricExporter{ + OTLP: &OTLPMetric{ + Protocol: "grpc/protobuf", + Endpoint: "localhost:4318", + Compression: ptr("none"), + Timeout: ptr(1000), + Headers: map[string]string{ + "test": "test1", + }, + TemporalityPreference: ptr("invalid"), + }, + }, + }, + }, + wantErr: errors.New("unsupported temporality preference \"invalid\""), + }, { name: "periodic/otlp-grpc-invalid-compression", reader: MetricReader{ @@ -414,6 +494,86 @@ func TestReader(t *testing.T) { }, wantReader: sdkmetric.NewPeriodicReader(otlpHTTPExporter), }, + { + name: "periodic/otlp-http-cumulative-temporality", + reader: MetricReader{ + Periodic: &PeriodicMetricReader{ + Exporter: MetricExporter{ + OTLP: &OTLPMetric{ + Protocol: "http/protobuf", + Endpoint: "localhost:4318", + Compression: ptr("none"), + Timeout: ptr(1000), + Headers: map[string]string{ + "test": "test1", + }, + TemporalityPreference: ptr("cumulative"), + }, + }, + }, + }, + wantReader: sdkmetric.NewPeriodicReader(otlpHTTPExporter), + }, + { + name: "periodic/otlp-http-lowmemory-temporality", + reader: MetricReader{ + Periodic: &PeriodicMetricReader{ + Exporter: MetricExporter{ + OTLP: &OTLPMetric{ + Protocol: "http/protobuf", + Endpoint: "localhost:4318", + Compression: ptr("none"), + Timeout: ptr(1000), + Headers: map[string]string{ + "test": "test1", + }, + TemporalityPreference: ptr("lowmemory"), + }, + }, + }, + }, + wantReader: sdkmetric.NewPeriodicReader(otlpHTTPExporter), + }, + { + name: "periodic/otlp-http-delta-temporality", + reader: MetricReader{ + Periodic: &PeriodicMetricReader{ + Exporter: MetricExporter{ + OTLP: &OTLPMetric{ + Protocol: "http/protobuf", + Endpoint: "localhost:4318", + Compression: ptr("none"), + Timeout: ptr(1000), + Headers: map[string]string{ + "test": "test1", + }, + TemporalityPreference: ptr("delta"), + }, + }, + }, + }, + wantReader: sdkmetric.NewPeriodicReader(otlpHTTPExporter), + }, + { + name: "periodic/otlp-http-invalid-temporality", + reader: MetricReader{ + Periodic: &PeriodicMetricReader{ + Exporter: MetricExporter{ + OTLP: &OTLPMetric{ + Protocol: "http/protobuf", + Endpoint: "localhost:4318", + Compression: ptr("none"), + Timeout: ptr(1000), + Headers: map[string]string{ + "test": "test1", + }, + TemporalityPreference: ptr("invalid"), + }, + }, + }, + }, + wantErr: errors.New("unsupported temporality preference \"invalid\""), + }, { name: "periodic/otlp-http-invalid-compression", reader: MetricReader{ From 1c2bc174e65c1febf748a06e8833caf7b5a7395a Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:43:16 -0700 Subject: [PATCH 2/2] add changelog Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dcd57e796a..08a578eb922 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Move examples from `go.opentelemetry.io/otel` to this repository under `examples` directory. (#6158) - Support yaml/json struct tags for generated code in `go.opentelemetry.io/contrib/config`. (#5433) - Add support for parsing YAML configuration via `ParseYAML` in `go.opentelemetry.io/contrib/config`. (#5433) +- Add support for temporality preference configuration in `go.opentelemetry.io/contrib/config`. (#5860) ### Changed