From 864bad93f88b597fe35046ac478fd5075d463f01 Mon Sep 17 00:00:00 2001 From: keisku Date: Fri, 23 May 2025 14:43:17 +0900 Subject: [PATCH] Prometheus exporter: omit empty otel_scope_info and otel_target_info metrics --- exporters/prometheus/exporter.go | 20 +++++++++++++------ exporters/prometheus/exporter_test.go | 4 +++- .../prometheus/testdata/empty_resource.txt | 9 --------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/exporters/prometheus/exporter.go b/exporters/prometheus/exporter.go index e0959641caf..44765703bcc 100644 --- a/exporters/prometheus/exporter.go +++ b/exporters/prometheus/exporter.go @@ -42,7 +42,9 @@ const ( ) var ( - errScopeInvalid = errors.New("invalid scope") + errScopeInvalid = errors.New("invalid scope") + errEmptyOtelScopeInfo = errors.New("empty otel_scope_info") + errEmptyOtelTargetInfo = errors.New("empty otel_target_info") metricsPool = sync.Pool{ New: func() interface{} { @@ -176,7 +178,7 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) { if c.targetInfo == nil && !c.disableTargetInfo { targetInfo, err := createInfoMetric(targetInfoMetricName, targetInfoDescription, metrics.Resource) if err != nil { - // If the target info metric is invalid, disable sending it. + // If the target info metric is invalid or empty, disable sending it. c.disableTargetInfo = true otel.Handle(err) return @@ -186,7 +188,7 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) { } }() - if !c.disableTargetInfo { + if !c.disableTargetInfo && c.targetInfo != nil { ch <- c.targetInfo } @@ -203,8 +205,8 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) { if !c.disableScopeInfo { scopeInfo, err := c.scopeInfo(scopeMetrics.Scope) - if errors.Is(err, errScopeInvalid) { - // Do not report the same error multiple times. + if errors.Is(err, errScopeInvalid) || scopeInfo == nil { + // Do not report the same error multiple times or if scopeInfo is nil. continue } if err != nil { @@ -435,13 +437,19 @@ func getAttrs(attrs attribute.Set) ([]string, []string) { } func createInfoMetric(name, description string, res *resource.Resource) (prometheus.Metric, error) { + if res.Set().Len() == 0 { + return nil, errEmptyOtelTargetInfo + } keys, values := getAttrs(*res.Set()) desc := prometheus.NewDesc(name, description, keys, nil) return prometheus.NewConstMetric(desc, prometheus.GaugeValue, float64(1), values...) } func createScopeInfoMetric(scope instrumentation.Scope) (prometheus.Metric, error) { - attrs := make([]attribute.KeyValue, 0, scope.Attributes.Len()+2) // resource attrs + scope name + scope version + if scope.Attributes.Len() == 0 { + return nil, errEmptyOtelScopeInfo + } + attrs := make([]attribute.KeyValue, 0, scope.Attributes.Len()+2) attrs = append(attrs, scope.Attributes.ToSlice()...) attrs = append(attrs, attribute.String(scopeNameLabel, scope.Name)) attrs = append(attrs, attribute.String(scopeVersionLabel, scope.Version)) diff --git a/exporters/prometheus/exporter_test.go b/exporters/prometheus/exporter_test.go index 19fe5b5a51d..793149e5417 100644 --- a/exporters/prometheus/exporter_test.go +++ b/exporters/prometheus/exporter_test.go @@ -305,7 +305,9 @@ func TestPrometheusExporter(t *testing.T) { name: "empty resource", emptyResource: true, expectedFile: "testdata/empty_resource.txt", - recordMetrics: func(ctx context.Context, meter otelmetric.Meter) { + recordMetrics: func(ctx context.Context, _ otelmetric.Meter) { + // No instrumentation name/version/attributes + meter := metric.NewMeterProvider().Meter("") opt := otelmetric.WithAttributes( attribute.Key("A").String("B"), attribute.Key("C").String("D"), diff --git a/exporters/prometheus/testdata/empty_resource.txt b/exporters/prometheus/testdata/empty_resource.txt index 5dbcfb3b8a4..e69de29bb2d 100755 --- a/exporters/prometheus/testdata/empty_resource.txt +++ b/exporters/prometheus/testdata/empty_resource.txt @@ -1,9 +0,0 @@ -# HELP foo_total a simple counter -# TYPE foo_total counter -foo_total{A="B",C="D",E="true",F="42",otel_scope_name="testmeter",otel_scope_version="v0.1.0"} 24.3 -# HELP otel_scope_info Instrumentation Scope metadata -# TYPE otel_scope_info gauge -otel_scope_info{fizz="buzz",otel_scope_name="testmeter",otel_scope_version="v0.1.0"} 1 -# HELP target_info Target metadata -# TYPE target_info gauge -target_info 1