diff --git a/pkg/otlp/model/translator/metrics_translator.go b/pkg/otlp/model/translator/metrics_translator.go index 6ec1f1c61338c..406d51b78bdd4 100644 --- a/pkg/otlp/model/translator/metrics_translator.go +++ b/pkg/otlp/model/translator/metrics_translator.go @@ -430,6 +430,8 @@ func (t *Translator) MapMetrics(ctx context.Context, md pdata.Metrics, consumer var additionalTags []string if t.cfg.InstrumentationLibraryMetadataAsTags { additionalTags = append(attributeTags, instrumentationlibrary.TagsFromInstrumentationLibraryMetadata(ilm.InstrumentationLibrary())...) + } else { + additionalTags = attributeTags } for k := 0; k < metricsArray.Len(); k++ { diff --git a/pkg/otlp/model/translator/metrics_translator_test.go b/pkg/otlp/model/translator/metrics_translator_test.go index 0643b5313c00a..174f14dd1ebef 100644 --- a/pkg/otlp/model/translator/metrics_translator_test.go +++ b/pkg/otlp/model/translator/metrics_translator_test.go @@ -16,6 +16,7 @@ package translator import ( "context" + "fmt" "math" "testing" "time" @@ -26,6 +27,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/model/pdata" + conventions "go.opentelemetry.io/collector/model/semconv/v1.5.0" "go.uber.org/zap" "go.uber.org/zap/zapcore" "go.uber.org/zap/zaptest/observer" @@ -106,12 +108,16 @@ func (t testProvider) Hostname(context.Context) (string, error) { return string(t), nil } -func newTranslator(t *testing.T, logger *zap.Logger) *Translator { - tr, err := New( - logger, +func newTranslator(t *testing.T, logger *zap.Logger, opts ...Option) *Translator { + options := append([]Option{ WithFallbackHostnameProvider(testProvider("fallbackHostname")), WithHistogramMode(HistogramModeDistributions), WithNumberMode(NumberModeCumulativeToDelta), + }, opts...) + + tr, err := New( + logger, + options..., ) require.NoError(t, err) @@ -934,16 +940,22 @@ const ( testHostname = "res-hostname" ) -func createTestMetrics() pdata.Metrics { +func createTestMetrics(additionalAttributes map[string]string, name, version string) pdata.Metrics { md := pdata.NewMetrics() rms := md.ResourceMetrics() rm := rms.AppendEmpty() attrs := rm.Resource().Attributes() attrs.InsertString(attributes.AttributeDatadogHostname, testHostname) + for attr, val := range additionalAttributes { + attrs.InsertString(attr, val) + } ilms := rm.InstrumentationLibraryMetrics() - metricsArray := ilms.AppendEmpty().Metrics() + ilm := ilms.AppendEmpty() + ilm.InstrumentationLibrary().SetName(name) + ilm.InstrumentationLibrary().SetVersion(version) + metricsArray := ilm.Metrics() metricsArray.AppendEmpty() // first one is TypeNone to test that it's ignored // IntGauge @@ -1096,64 +1108,203 @@ func createTestMetrics() pdata.Metrics { return md } -func newGaugeWithHostname(name string, val float64) metric { - m := newGauge(name, 0, val, []string{}) +func newGaugeWithHostname(name string, val float64, tags []string) metric { + m := newGauge(name, 0, val, tags) m.host = testHostname return m } -func newCountWithHostname(name string, val float64, seconds uint64) metric { - m := newCount(name, seconds*1e9, val, []string{}) +func newCountWithHostname(name string, val float64, seconds uint64, tags []string) metric { + m := newCount(name, seconds*1e9, val, tags) m.host = testHostname return m } -func newSketchWithHostname(name string, summary summary.Summary, seconds uint64) sketch { - s := newSketch(name, seconds, summary, []string{}) +func newSketchWithHostname(name string, summary summary.Summary, tags []string) sketch { + s := newSketch(name, 0, summary, tags) s.host = testHostname return s } func TestMapMetrics(t *testing.T) { - md := createTestMetrics() + attrs := map[string]string{ + conventions.AttributeDeploymentEnvironment: "dev", + "custom_attribute": "custom_value", + } + // When ResourceAttributesAsTags is true, attributes are + // converted into labels by the resourcetotelemetry helper, + // so MapMetrics doesn't do any conversion. + // When ResourceAttributesAsTags is false, attributes + // defined in internal/attributes get converted to tags. + // Other tags do not get converted. + attrTags := []string{ + "env:dev", + } - core, observed := observer.New(zapcore.DebugLevel) - testLogger := zap.New(core) - ctx := context.Background() - consumer := &mockFullConsumer{} - tr := newTranslator(t, testLogger) - err := tr.MapMetrics(ctx, md, consumer) - require.NoError(t, err) + ilName := "instrumentation_library" + ilVersion := "1.0.0" + ilTags := []string{ + fmt.Sprintf("instrumentation_library:%s", ilName), + fmt.Sprintf("instrumentation_library_version:%s", ilVersion), + } - assert.ElementsMatch(t, consumer.metrics, []metric{ - newGaugeWithHostname("int.gauge", 1), - newGaugeWithHostname("double.gauge", math.Pi), - newCountWithHostname("int.delta.sum", 2, 0), - newCountWithHostname("double.delta.sum", math.E, 0), - newCountWithHostname("int.delta.monotonic.sum", 2, 0), - newCountWithHostname("double.delta.monotonic.sum", math.E, 0), - newCountWithHostname("summary.sum", 10_000, 2), - newCountWithHostname("summary.count", 100, 2), - newGaugeWithHostname("int.cumulative.sum", 4), - newGaugeWithHostname("double.cumulative.sum", 4), - newCountWithHostname("int.cumulative.monotonic.sum", 3, 2), - newCountWithHostname("double.cumulative.monotonic.sum", math.Pi, 2), - }) + tests := []struct { + name string + resourceAttributesAsTags bool + instrumentationLibraryMetadataAsTags bool + expectedMetrics []metric + expectedSketches []sketch + expectedUnknownMetricType int + expectedUnsupportedAggregationTemporality int + }{ + { + name: "ResourceAttributesAsTags: false, InstrumentationLibraryMetadataAsTags: false", + resourceAttributesAsTags: false, + instrumentationLibraryMetadataAsTags: false, + expectedMetrics: []metric{ + newGaugeWithHostname("int.gauge", 1, attrTags), + newGaugeWithHostname("double.gauge", math.Pi, attrTags), + newCountWithHostname("int.delta.sum", 2, 0, attrTags), + newCountWithHostname("double.delta.sum", math.E, 0, attrTags), + newCountWithHostname("int.delta.monotonic.sum", 2, 0, attrTags), + newCountWithHostname("double.delta.monotonic.sum", math.E, 0, attrTags), + newCountWithHostname("summary.sum", 10_000, 2, attrTags), + newCountWithHostname("summary.count", 100, 2, attrTags), + newGaugeWithHostname("int.cumulative.sum", 4, attrTags), + newGaugeWithHostname("double.cumulative.sum", 4, attrTags), + newCountWithHostname("int.cumulative.monotonic.sum", 3, 2, attrTags), + newCountWithHostname("double.cumulative.monotonic.sum", math.Pi, 2, attrTags), + }, + expectedSketches: []sketch{ + newSketchWithHostname("double.histogram", summary.Summary{ + Min: 0, + Max: 0, + Sum: 0, + Avg: 0, + Cnt: 20, + }, attrTags), + }, + expectedUnknownMetricType: 1, + expectedUnsupportedAggregationTemporality: 2, + }, + { + name: "ResourceAttributesAsTags: true, InstrumentationLibraryMetadataAsTags: false", + resourceAttributesAsTags: true, + instrumentationLibraryMetadataAsTags: false, + expectedMetrics: []metric{ + newGaugeWithHostname("int.gauge", 1, []string{}), + newGaugeWithHostname("double.gauge", math.Pi, []string{}), + newCountWithHostname("int.delta.sum", 2, 0, []string{}), + newCountWithHostname("double.delta.sum", math.E, 0, []string{}), + newCountWithHostname("int.delta.monotonic.sum", 2, 0, []string{}), + newCountWithHostname("double.delta.monotonic.sum", math.E, 0, []string{}), + newCountWithHostname("summary.sum", 10_000, 2, []string{}), + newCountWithHostname("summary.count", 100, 2, []string{}), + newGaugeWithHostname("int.cumulative.sum", 4, []string{}), + newGaugeWithHostname("double.cumulative.sum", 4, []string{}), + newCountWithHostname("int.cumulative.monotonic.sum", 3, 2, []string{}), + newCountWithHostname("double.cumulative.monotonic.sum", math.Pi, 2, []string{}), + }, + expectedSketches: []sketch{ + newSketchWithHostname("double.histogram", summary.Summary{ + Min: 0, + Max: 0, + Sum: 0, + Avg: 0, + Cnt: 20, + }, []string{}), + }, + expectedUnknownMetricType: 1, + expectedUnsupportedAggregationTemporality: 2, + }, + { + name: "ResourceAttributesAsTags: false, InstrumentationLibraryMetadataAsTags: true", + resourceAttributesAsTags: false, + instrumentationLibraryMetadataAsTags: true, + expectedMetrics: []metric{ + newGaugeWithHostname("int.gauge", 1, append(attrTags, ilTags...)), + newGaugeWithHostname("double.gauge", math.Pi, append(attrTags, ilTags...)), + newCountWithHostname("int.delta.sum", 2, 0, append(attrTags, ilTags...)), + newCountWithHostname("double.delta.sum", math.E, 0, append(attrTags, ilTags...)), + newCountWithHostname("int.delta.monotonic.sum", 2, 0, append(attrTags, ilTags...)), + newCountWithHostname("double.delta.monotonic.sum", math.E, 0, append(attrTags, ilTags...)), + newCountWithHostname("summary.sum", 10_000, 2, append(attrTags, ilTags...)), + newCountWithHostname("summary.count", 100, 2, append(attrTags, ilTags...)), + newGaugeWithHostname("int.cumulative.sum", 4, append(attrTags, ilTags...)), + newGaugeWithHostname("double.cumulative.sum", 4, append(attrTags, ilTags...)), + newCountWithHostname("int.cumulative.monotonic.sum", 3, 2, append(attrTags, ilTags...)), + newCountWithHostname("double.cumulative.monotonic.sum", math.Pi, 2, append(attrTags, ilTags...)), + }, + expectedSketches: []sketch{ + newSketchWithHostname("double.histogram", summary.Summary{ + Min: 0, + Max: 0, + Sum: 0, + Avg: 0, + Cnt: 20, + }, append(attrTags, ilTags...)), + }, + expectedUnknownMetricType: 1, + expectedUnsupportedAggregationTemporality: 2, + }, + { + name: "ResourceAttributesAsTags: true, InstrumentationLibraryMetadataAsTags: true", + resourceAttributesAsTags: true, + instrumentationLibraryMetadataAsTags: true, + expectedMetrics: []metric{ + newGaugeWithHostname("int.gauge", 1, ilTags), + newGaugeWithHostname("double.gauge", math.Pi, ilTags), + newCountWithHostname("int.delta.sum", 2, 0, ilTags), + newCountWithHostname("double.delta.sum", math.E, 0, ilTags), + newCountWithHostname("int.delta.monotonic.sum", 2, 0, ilTags), + newCountWithHostname("double.delta.monotonic.sum", math.E, 0, ilTags), + newCountWithHostname("summary.sum", 10_000, 2, ilTags), + newCountWithHostname("summary.count", 100, 2, ilTags), + newGaugeWithHostname("int.cumulative.sum", 4, ilTags), + newGaugeWithHostname("double.cumulative.sum", 4, ilTags), + newCountWithHostname("int.cumulative.monotonic.sum", 3, 2, ilTags), + newCountWithHostname("double.cumulative.monotonic.sum", math.Pi, 2, ilTags), + }, + expectedSketches: []sketch{ + newSketchWithHostname("double.histogram", summary.Summary{ + Min: 0, + Max: 0, + Sum: 0, + Avg: 0, + Cnt: 20, + }, ilTags), + }, + expectedUnknownMetricType: 1, + expectedUnsupportedAggregationTemporality: 2, + }, + } - assert.ElementsMatch(t, consumer.sketches, []sketch{ - newSketchWithHostname("double.histogram", summary.Summary{ - Min: 0, - Max: 0, - Sum: 0, - Avg: 0, - Cnt: 20, - }, 0), - }) + for _, testInstance := range tests { + t.Run(testInstance.name, func(t *testing.T) { + md := createTestMetrics(attrs, ilName, ilVersion) - // One metric type was unknown or unsupported - assert.Equal(t, observed.FilterMessage("Unknown or unsupported metric type").Len(), 1) - // Two metric aggregation temporality was unknown or unsupported - assert.Equal(t, observed.FilterMessage("Unknown or unsupported aggregation temporality").Len(), 2) + core, observed := observer.New(zapcore.DebugLevel) + testLogger := zap.New(core) + ctx := context.Background() + consumer := &mockFullConsumer{} + + options := []Option{} + if testInstance.resourceAttributesAsTags { + options = append(options, WithResourceAttributesAsTags()) + } + if testInstance.instrumentationLibraryMetadataAsTags { + options = append(options, WithInstrumentationLibraryMetadataAsTags()) + } + tr := newTranslator(t, testLogger, options...) + err := tr.MapMetrics(ctx, md, consumer) + require.NoError(t, err) + + assert.ElementsMatch(t, consumer.metrics, testInstance.expectedMetrics) + assert.ElementsMatch(t, consumer.sketches, testInstance.expectedSketches) + assert.Equal(t, observed.FilterMessage("Unknown or unsupported metric type").Len(), testInstance.expectedUnknownMetricType) + assert.Equal(t, observed.FilterMessage("Unknown or unsupported aggregation temporality").Len(), testInstance.expectedUnsupportedAggregationTemporality) + }) + } } func createNaNMetrics() pdata.Metrics { @@ -1259,7 +1410,7 @@ func TestNaNMetrics(t *testing.T) { require.NoError(t, err) assert.ElementsMatch(t, consumer.metrics, []metric{ - newCountWithHostname("nan.summary.count", 100, 2), + newCountWithHostname("nan.summary.count", 100, 2, []string{}), }) assert.ElementsMatch(t, consumer.sketches, []sketch{ @@ -1269,7 +1420,7 @@ func TestNaNMetrics(t *testing.T) { Sum: 0, Avg: 0, Cnt: 20, - }, 0), + }, []string{}), }) // One metric type was unknown or unsupported