Skip to content

Commit 12a1810

Browse files
authored
[receiver/prometheus] Generate Scope Attributes from otel_scope_<attribute-name> labels (#46612)
#### Description Add support for extracting scope attributes from otel_scope_<attribute-name> labels on metrics in the Prometheus receiver, per the spec change. This is gated behind `receiver.prometheusreceiver.UseScopeAttributeLabels` (alpha, disabled by default). The gate acts as a switch: * Disabled (default): existing behavior — scope attributes come from otel_scope_info, and otel_scope_<attr> labels are treated as regular data point attributes. * Enabled: scope attributes are read from otel_scope_<attr> labels on every metric, otel_scope_info is ignored. #### Link to tracking issue Fixes #41502 #### Testing * Added integration tests (TestScopeAttributeLabelsFeatureGate) covering both gate states: enabled extracts scope attributes and splits scopes; disabled preserves otel_scope_* as regular labels. * Existing TestScopeInfoScopeAttributes and all internal tests pass unchanged. --------- Signed-off-by: Arthur Silva Sens <arthursens2005@gmail.com>
1 parent 2b3a1f0 commit 12a1810

12 files changed

Lines changed: 407 additions & 43 deletions
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. receiver/filelog)
7+
component: receiver/prometheus
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add support for reading instrumentation scope attributes from `otel_scope_<attribute-name>` labels while feature-gating deprecation of `otel_scope_info`.
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [41502]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext: |
19+
Scope attributes are always extracted from `otel_scope_<attribute-name>` labels on metrics.
20+
The `receiver.prometheusreceiver.IgnoreScopeInfoMetric` feature gate (alpha, disabled by default)
21+
controls only whether the legacy `otel_scope_info` metric is ignored for scope attribute extraction.
22+
When the gate is disabled, both mechanisms coexist to support migration.
23+
See the specification change for motivation: https://github.com/open-telemetry/opentelemetry-specification/pull/4505
24+
25+
# If your change doesn't affect end users or the exported elements of any package,
26+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
27+
# Optional: The change log or logs in which this entry should be included.
28+
# e.g. '[user]' or '[user, api]'
29+
# Include 'user' if the change is relevant to end users.
30+
# Include 'api' if there is a change to a library API.
31+
# Default: '[user]'
32+
change_logs: []

pkg/translator/prometheus/constants.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ const (
2020
// attributes in Prometheus format:
2121
// https://github.com/open-telemetry/opentelemetry-specification/blob/e6eccba97ebaffbbfad6d4358408a2cead0ec2df/specification/compatibility/prometheus_and_openmetrics.md#instrumentation-scope
2222
ScopeInfoMetricName = "otel_scope_info"
23+
// ScopeLabelPrefix prefixes instrumentation scope labels in Prometheus
24+
// format:
25+
// https://github.com/open-telemetry/opentelemetry-specification/blob/fd43145dde7e5192ebc59a20992d98a3e6af5553/specification/compatibility/prometheus_and_openmetrics.md#instrumentation-scope
26+
ScopeLabelPrefix = "otel_scope_"
2327
// ScopeNameLabelKey is the name of the label key used to identify the name
2428
// of the OpenTelemetry scope which produced the metric:
2529
// https://github.com/open-telemetry/opentelemetry-specification/blob/e6eccba97ebaffbbfad6d4358408a2cead0ec2df/specification/compatibility/prometheus_and_openmetrics.md#instrumentation-scope

receiver/prometheusreceiver/documentation.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ This component has the following feature gates:
1010
| ------------ | ----- | ----------- | ------------ | ---------- | --------- |
1111
| `receiver.prometheusreceiver.EnableCreatedTimestampZeroIngestion` | alpha | Enables the Prometheus created-timestamps-zero-injection feature. Created timestamps are injected as 0-valued samples when appropriate. This is disabled by default due to worse CPU performance with higher metric volumes. | v0.113.0 | N/A | [Link](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/40355) |
1212
| `receiver.prometheusreceiver.EnableNativeHistograms` | stable | Converts scraped Prometheus native histograms into OpenTelemetry exponential histograms. You still need to configure 'scrape_native_histograms: true' in your Prometheus scrape config to actually scrape native histograms. For mixed histograms (both classic and native), only the native histogram buckets are used. | v0.142.0 | v0.145.0 | [Link](https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/34473) |
13+
| `receiver.prometheusreceiver.IgnoreScopeInfoMetric` | alpha | When enabled, the `otel_scope_info` metric is ignored for scope attribute extraction. | v0.148.0 | N/A | [Link](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/41502) |
1314
| `receiver.prometheusreceiver.RemoveStartTimeAdjustment` | stable | When enabled, the Prometheus receiver will leave the start time unset. Use the metric_start_time processor instead if you need this functionality. | v0.121.0 | v0.142.0 | [Link](https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/36364) |
1415
| `receiver.prometheusreceiver.UseCreatedMetric` | deprecated | When enabled, the Prometheus receiver will retrieve the start time for Summary, Histogram and Sum metrics from _created metric. | v0.89.0 | v0.141.0 | [Link](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/21909) |
1516

receiver/prometheusreceiver/go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ require (
1111
github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853
1212
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f
1313
github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusremotewriteexporter v0.148.0
14+
github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.148.0
1415
github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.148.0
1516
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.148.0
17+
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.148.0
1618
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus v0.148.0
1719
github.com/prometheus/client_golang v1.23.2
1820
github.com/prometheus/common v0.67.5
@@ -211,7 +213,6 @@ require (
211213
github.com/oklog/ulid/v2 v2.1.1 // indirect
212214
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.148.0 // indirect
213215
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.148.0 // indirect
214-
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.148.0 // indirect
215216
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/resourcetotelemetry v0.148.0 // indirect
216217
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheusremotewrite v0.148.0 // indirect
217218
github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.148.0 // indirect

receiver/prometheusreceiver/internal/metadata/generated_feature_gates.go

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

receiver/prometheusreceiver/internal/metricfamily.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,9 @@ func populateAttributes(mType pmetric.MetricType, ls labels.Labels, dest pcommon
432432
if j < len(names) && l.Name == names[j] {
433433
return
434434
}
435+
if strings.HasPrefix(l.Name, prometheus.ScopeLabelPrefix) {
436+
return
437+
}
435438
if l.Value == "" {
436439
// empty label values should be omitted
437440
return

receiver/prometheusreceiver/internal/metricfamily_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ func TestMetricGroupData_toDistributionUnitTest(t *testing.T) {
257257
} else {
258258
lbls = tt.labels.Copy()
259259
}
260-
sRef, _ := getSeriesRef(nil, lbls, mp.mtype)
260+
sRef, _ := getSeriesRefWithoutScopeLabels(nil, lbls, mp.mtype)
261261
err := mp.addSeries(sRef, tv.metric, lbls, tv.at, tv.value)
262262
if tt.wantErr {
263263
if i != 0 {
@@ -405,7 +405,7 @@ func TestMetricGroupData_toNHCBDistributionUnitTest(t *testing.T) {
405405
for _, tt := range tests {
406406
t.Run(tt.name, func(t *testing.T) {
407407
mp := newMetricFamily(tt.metricName, mc, zap.NewNop(), false, false)
408-
sRef, _ := getSeriesRef(nil, tt.labels, mp.mtype)
408+
sRef, _ := getSeriesRefWithoutScopeLabels(nil, tt.labels, mp.mtype)
409409

410410
err := mp.addNHCBSeries(sRef, tt.metricName, tt.labels, tt.intervalStartTimeMs, tt.integerHistogram, tt.floatHistogram)
411411
require.NoError(t, err)
@@ -575,14 +575,14 @@ func TestMetricGroupData_toExponentialDistributionUnitTest(t *testing.T) {
575575
switch {
576576
case tv.integerHistogram != nil:
577577
mp.mtype = pmetric.MetricTypeExponentialHistogram
578-
sRef, _ := getSeriesRef(nil, lbls, mp.mtype)
578+
sRef, _ := getSeriesRefWithoutScopeLabels(nil, lbls, mp.mtype)
579579
err = mp.addExponentialHistogramSeries(sRef, tv.metric, lbls, tv.at, tv.integerHistogram, nil)
580580
case tv.floatHistogram != nil:
581581
mp.mtype = pmetric.MetricTypeExponentialHistogram
582-
sRef, _ := getSeriesRef(nil, lbls, mp.mtype)
582+
sRef, _ := getSeriesRefWithoutScopeLabels(nil, lbls, mp.mtype)
583583
err = mp.addExponentialHistogramSeries(sRef, tv.metric, lbls, tv.at, nil, tv.floatHistogram)
584584
default:
585-
sRef, _ := getSeriesRef(nil, lbls, mp.mtype)
585+
sRef, _ := getSeriesRefWithoutScopeLabels(nil, lbls, mp.mtype)
586586
err = mp.addSeries(sRef, tv.metric, lbls, tv.at, tv.value)
587587
}
588588
if tt.wantErr {
@@ -866,7 +866,7 @@ func TestMetricGroupData_toSummaryUnitTest(t *testing.T) {
866866
for _, lbs := range tt.labelsScrapes {
867867
for i, scrape := range lbs.scrapes {
868868
lb := lbs.labels.Copy()
869-
sRef, _ := getSeriesRef(nil, lb, mp.mtype)
869+
sRef, _ := getSeriesRefWithoutScopeLabels(nil, lb, mp.mtype)
870870
err := mp.addSeries(sRef, scrape.metric, lb, scrape.at, scrape.value)
871871
if tt.wantErr {
872872
// The first scrape won't have an error
@@ -1004,7 +1004,7 @@ func TestMetricGroupData_toNumberDataUnitTest(t *testing.T) {
10041004
mp := newMetricFamily(tt.metricKind, mc, zap.NewNop(), false, false)
10051005
for _, tv := range tt.scrapes {
10061006
lb := tt.labels.Copy()
1007-
sRef, _ := getSeriesRef(nil, lb, mp.mtype)
1007+
sRef, _ := getSeriesRefWithoutScopeLabels(nil, lb, mp.mtype)
10081008
require.NoError(t, mp.addSeries(sRef, tv.metric, lb, tv.at, tv.value))
10091009
}
10101010

receiver/prometheusreceiver/internal/transaction.go

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"errors"
99
"fmt"
1010
"math"
11+
"strings"
1112

1213
"github.com/prometheus/common/model"
1314
"github.com/prometheus/prometheus/model/exemplar"
@@ -25,6 +26,7 @@ import (
2526
"go.opentelemetry.io/collector/receiver/receiverhelper"
2627
"go.uber.org/zap"
2728

29+
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil"
2830
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus"
2931
mdata "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver/internal/metadata"
3032
)
@@ -56,6 +58,7 @@ type transaction struct {
5658
externalLabels labels.Labels
5759
nodeResources map[resourceKey]pcommon.Resource
5860
scopeAttributes map[resourceKey]map[scopeID]pcommon.Map
61+
ignoreScopeInfoMetric bool
5962
logger *zap.Logger
6063
buildInfo component.BuildInfo
6164
obsrecv *receiverhelper.ObsReport
@@ -69,6 +72,7 @@ type scopeID struct {
6972
name string
7073
version string
7174
schemaURL string
75+
attrsHash [16]byte
7276
}
7377

7478
func newTransaction(
@@ -81,19 +85,20 @@ func newTransaction(
8185
useMetadata bool,
8286
) *transaction {
8387
return &transaction{
84-
ctx: ctx,
85-
families: make(map[resourceKey]map[scopeID]map[metricFamilyKey]*metricFamily),
86-
isNew: true,
87-
trimSuffixes: trimSuffixes,
88-
useMetadata: useMetadata,
89-
sink: sink,
90-
externalLabels: externalLabels,
91-
logger: settings.Logger,
92-
buildInfo: settings.BuildInfo,
93-
obsrecv: obsrecv,
94-
bufBytes: make([]byte, 0, 1024),
95-
scopeAttributes: make(map[resourceKey]map[scopeID]pcommon.Map),
96-
nodeResources: map[resourceKey]pcommon.Resource{},
88+
ctx: ctx,
89+
families: make(map[resourceKey]map[scopeID]map[metricFamilyKey]*metricFamily),
90+
isNew: true,
91+
trimSuffixes: trimSuffixes,
92+
useMetadata: useMetadata,
93+
sink: sink,
94+
externalLabels: externalLabels,
95+
logger: settings.Logger,
96+
buildInfo: settings.BuildInfo,
97+
obsrecv: obsrecv,
98+
bufBytes: make([]byte, 0, 1024),
99+
scopeAttributes: make(map[resourceKey]map[scopeID]pcommon.Map),
100+
ignoreScopeInfoMetric: mdata.ReceiverPrometheusreceiverIgnoreScopeInfoMetricFeatureGate.IsEnabled(),
101+
nodeResources: map[resourceKey]pcommon.Resource{},
97102
}
98103
}
99104

@@ -157,12 +162,13 @@ func (t *transaction) Append(_ storage.SeriesRef, ls labels.Labels, atMs int64,
157162
}
158163

159164
// For the `otel_scope_info` metric we need to convert it to scope attributes.
160-
if metricName == prometheus.ScopeInfoMetricName {
165+
if metricName == prometheus.ScopeInfoMetricName && !t.ignoreScopeInfoMetric {
161166
t.addScopeInfo(*rKey, ls)
162167
return 0, nil
163168
}
164169

165-
scope := getScopeID(ls)
170+
scope, attrs := getScopeID(ls)
171+
t.addScopeAttributesFromLabels(*rKey, scope, attrs)
166172

167173
if value.IsStaleNaN(val) {
168174
if t.detectAndStoreNativeHistogramStaleness(atMs, rKey, scope, metricName, ls) {
@@ -278,7 +284,9 @@ func (t *transaction) AppendExemplar(_ storage.SeriesRef, l labels.Labels, e exe
278284
return 0, errMetricNameNotFound
279285
}
280286

281-
mf := t.getOrCreateMetricFamily(*rKey, getScopeID(l), mn)
287+
scope, attrs := getScopeID(l)
288+
t.addScopeAttributesFromLabels(*rKey, scope, attrs)
289+
mf := t.getOrCreateMetricFamily(*rKey, scope, mn)
282290
mf.addExemplar(t.getSeriesRef(l, mf.mtype), e)
283291

284292
return 0, nil
@@ -329,7 +337,9 @@ func (t *transaction) AppendHistogram(_ storage.SeriesRef, ls labels.Labels, atM
329337
// The `up`, `target_info`, `otel_scope_info` metrics should never generate native histograms,
330338
// thus we don't check for them here as opposed to the Append function.
331339

332-
curMF := t.getOrCreateMetricFamily(*rKey, getScopeID(ls), metricName)
340+
scope, attrs := getScopeID(ls)
341+
t.addScopeAttributesFromLabels(*rKey, scope, attrs)
342+
curMF := t.getOrCreateMetricFamily(*rKey, scope, metricName)
333343
seriesRef := t.getSeriesRef(ls, curMF.mtype)
334344
cacheRef := ls.Hash()
335345

@@ -405,7 +415,9 @@ func (t *transaction) setStartTimestamp(ls labels.Labels, atMs, stMs int64) (sto
405415
return 0, errMetricNameNotFound
406416
}
407417

408-
curMF := t.getOrCreateMetricFamily(*rKey, getScopeID(ls), metricName)
418+
scope, attrs := getScopeID(ls)
419+
t.addScopeAttributesFromLabels(*rKey, scope, attrs)
420+
curMF := t.getOrCreateMetricFamily(*rKey, scope, metricName)
409421

410422
seriesRef := t.getSeriesRef(ls, curMF.mtype)
411423
curMF.addCreationTimestamp(seriesRef, ls, atMs, stMs)
@@ -418,8 +430,8 @@ func (*transaction) SetOptions(_ *storage.AppendOptions) {
418430
}
419431

420432
func (t *transaction) getSeriesRef(ls labels.Labels, mtype pmetric.MetricType) uint64 {
421-
var hash uint64
422-
hash, t.bufBytes = getSeriesRef(t.bufBytes, ls, mtype)
433+
hash, bufBytes := getSeriesRefWithoutScopeLabels(t.bufBytes, ls, mtype)
434+
t.bufBytes = bufBytes
423435
return hash
424436
}
425437

@@ -457,8 +469,6 @@ func (t *transaction) getMetrics() (pmetric.Metrics, error) {
457469
if scope.schemaURL != "" {
458470
ils.SetSchemaUrl(scope.schemaURL)
459471
}
460-
// If we got an otel_scope_info metric for that scope, get scope
461-
// attributes from it.
462472
if scopeAttributes, ok := t.scopeAttributes[rKey]; ok {
463473
if attributes, ok := scopeAttributes[scope]; ok {
464474
attributes.CopyTo(ils.Scope().Attributes())
@@ -489,20 +499,44 @@ func (t *transaction) getMetrics() (pmetric.Metrics, error) {
489499
return md, nil
490500
}
491501

492-
func getScopeID(ls labels.Labels) scopeID {
502+
func getScopeID(ls labels.Labels) (scopeID, pcommon.Map) {
493503
var scope scopeID
504+
attrs := pcommon.NewMap()
494505
ls.Range(func(lbl labels.Label) {
495-
if lbl.Name == prometheus.ScopeNameLabelKey {
506+
switch lbl.Name {
507+
case prometheus.ScopeNameLabelKey:
496508
scope.name = lbl.Value
497-
}
498-
if lbl.Name == prometheus.ScopeVersionLabelKey {
509+
return
510+
case prometheus.ScopeVersionLabelKey:
499511
scope.version = lbl.Value
500-
}
501-
if lbl.Name == prometheus.ScopeSchemaURLLabelKey {
512+
return
513+
case prometheus.ScopeSchemaURLLabelKey:
502514
scope.schemaURL = lbl.Value
515+
return
516+
}
517+
if !strings.HasPrefix(lbl.Name, prometheus.ScopeLabelPrefix) {
518+
return
503519
}
520+
attrKey := strings.TrimPrefix(lbl.Name, prometheus.ScopeLabelPrefix)
521+
attrs.PutStr(attrKey, lbl.Value)
504522
})
505-
return scope
523+
scope.attrsHash = pdatautil.MapHash(attrs)
524+
return scope, attrs
525+
}
526+
527+
func (t *transaction) addScopeAttributesFromLabels(key resourceKey, scope scopeID, attrs pcommon.Map) {
528+
if attrs.Len() == 0 {
529+
return
530+
}
531+
if _, ok := t.scopeAttributes[key]; !ok {
532+
t.scopeAttributes[key] = make(map[scopeID]pcommon.Map)
533+
}
534+
if _, exists := t.scopeAttributes[key][scope]; exists {
535+
return
536+
}
537+
copied := pcommon.NewMap()
538+
attrs.CopyTo(copied)
539+
t.scopeAttributes[key][scope] = copied
506540
}
507541

508542
func (t *transaction) initTransaction(lbs labels.Labels) (*resourceKey, error) {
@@ -637,6 +671,6 @@ func (t *transaction) addScopeInfo(key resourceKey, ls labels.Labels) {
637671
t.scopeAttributes[key][scope] = attrs
638672
}
639673

640-
func getSeriesRef(bytes []byte, ls labels.Labels, mtype pmetric.MetricType) (uint64, []byte) {
641-
return ls.HashWithoutLabels(bytes, getSortedNotUsefulLabels(mtype)...)
674+
func getSeriesRefWithoutScopeLabels(bytes []byte, ls labels.Labels, mtype pmetric.MetricType) (uint64, []byte) {
675+
return ls.HashWithoutLabels(bytes, getSortedNotUsefulLabelsForSeries(mtype, ls)...)
642676
}

receiver/prometheusreceiver/internal/transaction_test.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import (
2727
"go.opentelemetry.io/collector/receiver/receivertest"
2828
"go.uber.org/zap"
2929
"go.uber.org/zap/zaptest/observer"
30+
31+
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus"
3032
)
3133

3234
const (
@@ -2044,7 +2046,7 @@ func TestGetOrCreateMetricFamily_DistinctFamiliesForNativeVsClassic(t *testing.T
20442046
}
20452047

20462048
func TestGetSeriesRef_IgnoresNotUsefulLabels(t *testing.T) {
2047-
// Build two label sets that differ only in labels likely excluded by getSortedNotUsefulLabels (e.g., _otel_* scope labels)
2049+
// Build two label sets that differ only in scope labels, which are excluded from series identity.
20482050
lsA := labels.FromStrings(
20492051
string(model.MetricNameLabel), "metric_x",
20502052
"env", "prod",
@@ -2058,12 +2060,25 @@ func TestGetSeriesRef_IgnoresNotUsefulLabels(t *testing.T) {
20582060
)
20592061

20602062
var buf []byte
2061-
hashA, buf := getSeriesRef(buf, lsA, pmetric.MetricTypeSum)
2062-
hashB, _ := getSeriesRef(buf, lsB, pmetric.MetricTypeSum)
2063+
hashA, buf := getSeriesRefWithoutScopeLabels(buf, lsA, pmetric.MetricTypeSum)
2064+
hashB, _ := getSeriesRefWithoutScopeLabels(buf, lsB, pmetric.MetricTypeSum)
20632065

20642066
require.Equal(t, hashA, hashB, "series ref should be equal when differing only by excluded labels")
20652067
}
20662068

2069+
func TestGetScopeID_EmptyScopeAttributesUseZeroHash(t *testing.T) {
2070+
scope, attrs := getScopeID(labels.FromStrings(
2071+
string(model.MetricNameLabel), "metric_x",
2072+
prometheus.ScopeNameLabelKey, "scope.with.info",
2073+
prometheus.ScopeVersionLabelKey, "v1.0.0",
2074+
))
2075+
2076+
require.Equal(t, "scope.with.info", scope.name)
2077+
require.Equal(t, "v1.0.0", scope.version)
2078+
require.Zero(t, scope.attrsHash)
2079+
require.Zero(t, attrs.Len())
2080+
}
2081+
20672082
func TestAddTargetInfo_DoesNotCopyJobInstanceOrMetricName(t *testing.T) {
20682083
tr := newTxn(t, false)
20692084
rk := resourceKey{job: "job-a", instance: "localhost:1234"}

0 commit comments

Comments
 (0)