From 664a075380b9eb155512adb1213ca688bd1ed611 Mon Sep 17 00:00:00 2001 From: Travis Thompson Date: Thu, 24 Oct 2024 00:44:02 -0700 Subject: [PATCH] Fix exemplars being added to gauge metrics in the prometheus exporter (#5912) Prometheus Gauge metrics don't support exemplars and while `addGaugeMetric()` doesn't add them, `addSumMetric()` will if the metric is monotonic. This causes the prometheus client to throw an error: ``` * error collecting metric Desc{fqName: "http_server_request_body_size_bytes", help: "Measures size of RPC request messages (uncompressed).", constLabels: {}, variableLabels: {net_protocol_name,net_protocol_version,http_method,http_route,http_scheme,net_host_name,net_host_port,otel_scope_name,otel_scope_version}}: cannot inject exemplar into Gauge, Summary or Untyped ``` --------- Co-authored-by: Damien Mathieu <42@dmathieu.com> Co-authored-by: David Ashpole --- CHANGELOG.md | 1 + exporters/prometheus/exporter.go | 6 +++- exporters/prometheus/exporter_test.go | 36 +++++++++++++++++++ ...n_monotonic_sum_does_not_add_exemplars.txt | 10 ++++++ 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 exporters/prometheus/testdata/non_monotonic_sum_does_not_add_exemplars.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 99caa347000..b8eb772a62a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Fixed - Global MeterProvider registration unwraps global instrument Observers, the undocumented Unwrap() methods are now private. (#5881) +- Fix `go.opentelemetry.io/otel/exporters/prometheus` trying to add exemplars to Gauge metrics, which is unsupported. (#5912) ### Changed diff --git a/exporters/prometheus/exporter.go b/exporters/prometheus/exporter.go index b0f5f3730d5..98e3bbd2e9b 100644 --- a/exporters/prometheus/exporter.go +++ b/exporters/prometheus/exporter.go @@ -277,7 +277,11 @@ func addSumMetric[N int64 | float64](ch chan<- prometheus.Metric, sum metricdata otel.Handle(err) continue } - m = addExemplars(m, dp.Exemplars) + // GaugeValues don't support Exemplars at this time + // https://github.com/prometheus/client_golang/blob/aef8aedb4b6e1fb8ac1c90790645169125594096/prometheus/metric.go#L199 + if valueType != prometheus.GaugeValue { + m = addExemplars(m, dp.Exemplars) + } ch <- m } } diff --git a/exporters/prometheus/exporter_test.go b/exporters/prometheus/exporter_test.go index 36b27e3ac62..ad3444a9920 100644 --- a/exporters/prometheus/exporter_test.go +++ b/exporters/prometheus/exporter_test.go @@ -431,6 +431,42 @@ func TestPrometheusExporter(t *testing.T) { counter.Add(ctx, 5, otelmetric.WithAttributeSet(attrs2)) }, }, + { + name: "non-monotonic sum does not add exemplars", + expectedFile: "testdata/non_monotonic_sum_does_not_add_exemplars.txt", + recordMetrics: func(ctx context.Context, meter otelmetric.Meter) { + sc := trace.NewSpanContext(trace.SpanContextConfig{ + SpanID: trace.SpanID{0o1}, + TraceID: trace.TraceID{0o1}, + TraceFlags: trace.FlagsSampled, + }) + ctx = trace.ContextWithSpanContext(ctx, sc) + opt := otelmetric.WithAttributes( + attribute.Key("A").String("B"), + attribute.Key("C").String("D"), + attribute.Key("E").Bool(true), + attribute.Key("F").Int(42), + ) + counter, err := meter.Float64UpDownCounter( + "foo", + otelmetric.WithDescription("a simple up down counter"), + otelmetric.WithUnit("s"), + ) + require.NoError(t, err) + counter.Add(ctx, 5, opt) + counter.Add(ctx, 10.3, opt) + counter.Add(ctx, 9, opt) + counter.Add(ctx, -1, opt) + + attrs2 := attribute.NewSet( + attribute.Key("A").String("D"), + attribute.Key("C").String("B"), + attribute.Key("E").Bool(true), + attribute.Key("F").Int(42), + ) + counter.Add(ctx, 5, otelmetric.WithAttributeSet(attrs2)) + }, + }, } for _, tc := range testCases { diff --git a/exporters/prometheus/testdata/non_monotonic_sum_does_not_add_exemplars.txt b/exporters/prometheus/testdata/non_monotonic_sum_does_not_add_exemplars.txt new file mode 100644 index 00000000000..7eb6cec40e2 --- /dev/null +++ b/exporters/prometheus/testdata/non_monotonic_sum_does_not_add_exemplars.txt @@ -0,0 +1,10 @@ +# HELP foo_seconds a simple up down counter +# TYPE foo_seconds gauge +foo_seconds{A="B",C="D",E="true",F="42",otel_scope_name="testmeter",otel_scope_version="v0.1.0"} 23.3 +foo_seconds{A="D",C="B",E="true",F="42",otel_scope_name="testmeter",otel_scope_version="v0.1.0"} 5 +# HELP otel_scope_info Instrumentation Scope metadata +# TYPE otel_scope_info gauge +otel_scope_info{otel_scope_name="testmeter",otel_scope_version="v0.1.0"} 1 +# HELP target_info Target metadata +# TYPE target_info gauge +target_info{service_name="prometheus_test",telemetry_sdk_language="go",telemetry_sdk_name="opentelemetry",telemetry_sdk_version="latest"} 1