mirror of
https://github.com/prometheus/prometheus.git
synced 2026-02-03 20:39:32 -05:00
otlptranslator: filter __name__ from OTLP attributes to prevent duplicates (#17917)
Some checks are pending
buf.build / lint and publish (push) Waiting to run
CI / Go tests (push) Waiting to run
CI / More Go tests (push) Waiting to run
CI / Go tests with previous Go version (push) Waiting to run
CI / UI tests (push) Waiting to run
CI / Go tests on Windows (push) Waiting to run
CI / Mixins tests (push) Waiting to run
CI / Build Prometheus for common architectures (push) Waiting to run
CI / Build Prometheus for all architectures (push) Waiting to run
CI / Report status of build Prometheus for all architectures (push) Blocked by required conditions
CI / Check generated parser (push) Waiting to run
CI / golangci-lint (push) Waiting to run
CI / fuzzing (push) Waiting to run
CI / codeql (push) Waiting to run
CI / Publish main branch artifacts (push) Blocked by required conditions
CI / Publish release artefacts (push) Blocked by required conditions
CI / Publish UI on npm Registry (push) Blocked by required conditions
Scorecards supply-chain security / Scorecards analysis (push) Waiting to run
Some checks are pending
buf.build / lint and publish (push) Waiting to run
CI / Go tests (push) Waiting to run
CI / More Go tests (push) Waiting to run
CI / Go tests with previous Go version (push) Waiting to run
CI / UI tests (push) Waiting to run
CI / Go tests on Windows (push) Waiting to run
CI / Mixins tests (push) Waiting to run
CI / Build Prometheus for common architectures (push) Waiting to run
CI / Build Prometheus for all architectures (push) Waiting to run
CI / Report status of build Prometheus for all architectures (push) Blocked by required conditions
CI / Check generated parser (push) Waiting to run
CI / golangci-lint (push) Waiting to run
CI / fuzzing (push) Waiting to run
CI / codeql (push) Waiting to run
CI / Publish main branch artifacts (push) Blocked by required conditions
CI / Publish release artefacts (push) Blocked by required conditions
CI / Publish UI on npm Registry (push) Blocked by required conditions
Scorecards supply-chain security / Scorecards analysis (push) Waiting to run
* otlptranslator: filter __name__ from OTLP attributes to prevent duplicates OTLP metrics can have a __name__ attribute which, when combined with the metric name passed via extras, creates duplicate __name__ labels. This commit implements filtering out of any __name__ metric attribute from OTLP. Also rename TestCreateAttributes to TestPrometheusConverter_createAttributes for consistency, and add test cases for __name__, __type__, and __unit__ OTLP metric attributes. --------- Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
This commit is contained in:
parent
bec70227f1
commit
2332962c4b
4 changed files with 129 additions and 7 deletions
|
|
@ -61,6 +61,13 @@ const (
|
|||
defaultLookbackDelta = 5 * time.Minute
|
||||
)
|
||||
|
||||
// reservedLabelNames contains label names that should be filtered from
|
||||
// OTLP attributes because they are set separately (via extras parameter).
|
||||
// Allowing these through could create duplicate labels.
|
||||
var reservedLabelNames = []string{
|
||||
model.MetricNameLabel, // "__name__" - set from metric name
|
||||
}
|
||||
|
||||
// createAttributes creates a slice of Prometheus Labels with OTLP attributes and pairs of string values.
|
||||
// Unpaired string values are ignored. String pairs overwrite OTLP labels if collisions happen and
|
||||
// if logOnOverwrite is true, the overwrite is logged. Resulting label names are sanitized.
|
||||
|
|
@ -214,7 +221,7 @@ func (c *PrometheusConverter) addHistogramDataPoints(ctx context.Context, dataPo
|
|||
pt := dataPoints.At(x)
|
||||
timestamp := convertTimeStamp(pt.Timestamp())
|
||||
startTimestamp := convertTimeStamp(pt.StartTimestamp())
|
||||
baseLabels, err := c.createAttributes(pt.Attributes(), settings, nil, false, meta)
|
||||
baseLabels, err := c.createAttributes(pt.Attributes(), settings, reservedLabelNames, false, meta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -416,7 +423,7 @@ func (c *PrometheusConverter) addSummaryDataPoints(ctx context.Context, dataPoin
|
|||
pt := dataPoints.At(x)
|
||||
timestamp := convertTimeStamp(pt.Timestamp())
|
||||
startTimestamp := convertTimeStamp(pt.StartTimestamp())
|
||||
baseLabels, err := c.createAttributes(pt.Attributes(), settings, nil, false, meta)
|
||||
baseLabels, err := c.createAttributes(pt.Attributes(), settings, reservedLabelNames, false, meta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,11 +31,12 @@ import (
|
|||
|
||||
"github.com/prometheus/prometheus/config"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/model/metadata"
|
||||
"github.com/prometheus/prometheus/prompb"
|
||||
"github.com/prometheus/prometheus/util/testutil"
|
||||
)
|
||||
|
||||
func TestCreateAttributes(t *testing.T) {
|
||||
func TestPrometheusConverter_createAttributes(t *testing.T) {
|
||||
resourceAttrs := map[string]string{
|
||||
"service.name": "service name",
|
||||
"service.instance.id": "service ID",
|
||||
|
|
@ -386,6 +387,18 @@ func TestCreateAttributes(t *testing.T) {
|
|||
"metric_multi", "multi metric",
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "__name__ attribute is filtered when passed in ignoreAttrs",
|
||||
promoteResourceAttributes: nil,
|
||||
ignoreAttrs: []string{model.MetricNameLabel},
|
||||
expectedLabels: labels.FromStrings(
|
||||
"__name__", "test_metric",
|
||||
"instance", "service ID",
|
||||
"job", "service name",
|
||||
"metric_attr", "metric value",
|
||||
"metric_attr_other", "metric value other",
|
||||
),
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
|
|
@ -423,6 +436,108 @@ func TestCreateAttributes(t *testing.T) {
|
|||
testutil.RequireEqual(t, tc.expectedLabels, lbls)
|
||||
})
|
||||
}
|
||||
|
||||
// Test that __name__ attributes in OTLP data are filtered out to prevent
|
||||
// duplicate labels.
|
||||
t.Run("__name__ attribute in OTLP data is filtered", func(t *testing.T) {
|
||||
resource := pcommon.NewResource()
|
||||
resource.Attributes().PutStr("service.name", "test-service")
|
||||
resource.Attributes().PutStr("service.instance.id", "test-instance")
|
||||
|
||||
// Create attributes with __name__ to simulate problematic OTLP data.
|
||||
attrsWithNameLabel := pcommon.NewMap()
|
||||
attrsWithNameLabel.PutStr("__name__", "wrong_metric_name")
|
||||
attrsWithNameLabel.PutStr("other_attr", "value")
|
||||
|
||||
mockAppender := &mockCombinedAppender{}
|
||||
c := NewPrometheusConverter(mockAppender)
|
||||
settings := Settings{}
|
||||
|
||||
require.NoError(t, c.setResourceContext(resource, settings))
|
||||
require.NoError(t, c.setScopeContext(scope{}, settings))
|
||||
|
||||
// Call createAttributes with reservedLabelNames to filter __name__.
|
||||
lbls, err := c.createAttributes(
|
||||
attrsWithNameLabel,
|
||||
settings,
|
||||
reservedLabelNames,
|
||||
true,
|
||||
Metadata{},
|
||||
model.MetricNameLabel, "correct_metric_name",
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify there's exactly one __name__ label with the correct value.
|
||||
nameCount := 0
|
||||
var nameValue string
|
||||
lbls.Range(func(l labels.Label) {
|
||||
if l.Name == model.MetricNameLabel {
|
||||
nameCount++
|
||||
nameValue = l.Value
|
||||
}
|
||||
})
|
||||
|
||||
require.Equal(t, 1, nameCount)
|
||||
require.Equal(t, "correct_metric_name", nameValue)
|
||||
require.Equal(t, "value", lbls.Get("other_attr"))
|
||||
})
|
||||
|
||||
// Test that __type__ and __unit__ attributes in OTLP data are overwritten
|
||||
// by auto-generated labels from metadata when EnableTypeAndUnitLabels is true.
|
||||
t.Run("__type__ and __unit__ attributes are overwritten by metadata", func(t *testing.T) {
|
||||
resource := pcommon.NewResource()
|
||||
resource.Attributes().PutStr("service.name", "test-service")
|
||||
resource.Attributes().PutStr("service.instance.id", "test-instance")
|
||||
|
||||
// Create attributes with __type__ and __unit__ to simulate problematic OTLP data.
|
||||
attrsWithTypeAndUnit := pcommon.NewMap()
|
||||
attrsWithTypeAndUnit.PutStr(model.MetricTypeLabel, "wrong_type")
|
||||
attrsWithTypeAndUnit.PutStr(model.MetricUnitLabel, "wrong_unit")
|
||||
attrsWithTypeAndUnit.PutStr("other_attr", "value")
|
||||
|
||||
mockAppender := &mockCombinedAppender{}
|
||||
c := NewPrometheusConverter(mockAppender)
|
||||
settings := Settings{EnableTypeAndUnitLabels: true}
|
||||
|
||||
require.NoError(t, c.setResourceContext(resource, settings))
|
||||
require.NoError(t, c.setScopeContext(scope{}, settings))
|
||||
|
||||
// Call createAttributes with Metadata containing correct Type and Unit.
|
||||
lbls, err := c.createAttributes(
|
||||
attrsWithTypeAndUnit,
|
||||
settings,
|
||||
reservedLabelNames,
|
||||
true,
|
||||
Metadata{Metadata: metadata.Metadata{Type: model.MetricTypeGauge, Unit: "seconds"}},
|
||||
model.MetricNameLabel, "test_metric",
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify there's exactly one __type__ label with the correct value (from metadata).
|
||||
typeCount := 0
|
||||
var typeValue string
|
||||
lbls.Range(func(l labels.Label) {
|
||||
if l.Name == model.MetricTypeLabel {
|
||||
typeCount++
|
||||
typeValue = l.Value
|
||||
}
|
||||
})
|
||||
require.Equal(t, 1, typeCount)
|
||||
require.Equal(t, "gauge", typeValue)
|
||||
|
||||
// Verify there's exactly one __unit__ label with the correct value (from metadata).
|
||||
unitCount := 0
|
||||
var unitValue string
|
||||
lbls.Range(func(l labels.Label) {
|
||||
if l.Name == model.MetricUnitLabel {
|
||||
unitCount++
|
||||
unitValue = l.Value
|
||||
}
|
||||
})
|
||||
require.Equal(t, 1, unitCount)
|
||||
require.Equal(t, "seconds", unitValue)
|
||||
require.Equal(t, "value", lbls.Get("other_attr"))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_convertTimeStamp(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ func (c *PrometheusConverter) addExponentialHistogramDataPoints(ctx context.Cont
|
|||
lbls, err := c.createAttributes(
|
||||
pt.Attributes(),
|
||||
settings,
|
||||
nil,
|
||||
reservedLabelNames,
|
||||
true,
|
||||
meta,
|
||||
model.MetricNameLabel,
|
||||
|
|
@ -269,7 +269,7 @@ func (c *PrometheusConverter) addCustomBucketsHistogramDataPoints(ctx context.Co
|
|||
lbls, err := c.createAttributes(
|
||||
pt.Attributes(),
|
||||
settings,
|
||||
nil,
|
||||
reservedLabelNames,
|
||||
true,
|
||||
meta,
|
||||
model.MetricNameLabel,
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ func (c *PrometheusConverter) addGaugeNumberDataPoints(ctx context.Context, data
|
|||
labels, err := c.createAttributes(
|
||||
pt.Attributes(),
|
||||
settings,
|
||||
nil,
|
||||
reservedLabelNames,
|
||||
true,
|
||||
meta,
|
||||
model.MetricNameLabel,
|
||||
|
|
@ -79,7 +79,7 @@ func (c *PrometheusConverter) addSumNumberDataPoints(ctx context.Context, dataPo
|
|||
lbls, err := c.createAttributes(
|
||||
pt.Attributes(),
|
||||
settings,
|
||||
nil,
|
||||
reservedLabelNames,
|
||||
true,
|
||||
meta,
|
||||
model.MetricNameLabel,
|
||||
|
|
|
|||
Loading…
Reference in a new issue