diff --git a/CHANGELOG.md b/CHANGELOG.md index e048046e3d78..72d93d93d975 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### 🚩 Deprecations 🚩 +- `datadogexporter`: Deprecate `instrumentation_library_metadata_as_tags` (#11135) - `datadogexporter`: Deprecate `Sanitize` method of `Config` struct (#8829) - `observiqexporter`: Deprecate the observiq exporter (#10977) - `honeycombexporter`: Deprecate honeycomb exporter (#10318) @@ -32,6 +33,7 @@ - `tailsamplingprocessor`: New sampler added that allows to sample based on minimum number of spans - `datadogexporter`: Some config validation and unmarshaling steps are now done on `Validate` and `Unmarshal` instead of `Sanitize` (#8829) - `datadogexporter`: Add `exporter.datadog.hostname.preview` feature flag and related warnings (#10926) +- `datadogexporter`: Add `instrumentation_scope_metadata_as_tags` instead of `instrumentation_library_metadata_as_tags` in favor of https://github.com/open-telemetry/opentelemetry-proto/releases/tag/v0.15.0 (#11135) - `examples`: Add an example for scraping Couchbase metrics (#10894) - `filestorageextension`: Add background compaction capability (#9327) - `googlecloudpubsubreceiver`: Added new `Endpoint` and `Insecure` connection configuration options. (#10845) diff --git a/exporter/datadogexporter/config/config.go b/exporter/datadogexporter/config/config.go index 5f659262cadf..0690a2877fab 100644 --- a/exporter/datadogexporter/config/config.go +++ b/exporter/datadogexporter/config/config.go @@ -224,9 +224,15 @@ type MetricsExporterConfig struct { // resource attributes into metric labels, which are then converted into tags ResourceAttributesAsTags bool `mapstructure:"resource_attributes_as_tags"` + // Deprecated: [0.54.0] Use InstrumentationScopeMetadataAsTags instead in favor of https://github.com/open-telemetry/opentelemetry-proto/releases/tag/v0.15.0 + // Both must not be enabled at the same time. // InstrumentationLibraryMetadataAsTags, if set to true, adds the name and version of the // instrumentation library that created a metric to the metric tags InstrumentationLibraryMetadataAsTags bool `mapstructure:"instrumentation_library_metadata_as_tags"` + + // InstrumentationScopeMetadataAsTags, if set to true, adds the name and version of the + // instrumentation scope that created a metric to the metric tags + InstrumentationScopeMetadataAsTags bool `mapstructure:"instrumentation_scope_metadata_as_tags"` } // TracesConfig defines the traces exporter specific configuration options diff --git a/exporter/datadogexporter/config/warn_envvars.go b/exporter/datadogexporter/config/warn_envvars.go index 76392741d751..da16ea84bf51 100644 --- a/exporter/datadogexporter/config/warn_envvars.go +++ b/exporter/datadogexporter/config/warn_envvars.go @@ -49,6 +49,7 @@ func futureDefaultConfig() *Config { ExporterConfig: MetricsExporterConfig{ ResourceAttributesAsTags: false, InstrumentationLibraryMetadataAsTags: false, + InstrumentationScopeMetadataAsTags: false, }, HistConfig: HistogramConfig{ Mode: "distributions", diff --git a/exporter/datadogexporter/example/config.yaml b/exporter/datadogexporter/example/config.yaml index cfbb98a7d588..565d687c42a8 100644 --- a/exporter/datadogexporter/example/config.yaml +++ b/exporter/datadogexporter/example/config.yaml @@ -55,7 +55,7 @@ exporters: ## @params use_resource_metadata - boolean - optional - default: true ## Deprecated: [v0.49.0] Use `host_metadata::hostname_source` instead. ## This option will be removed in v0.52.0. - # + # # use_resource_metadata: true ## @param only_metadata - boolean - optional - default: false @@ -132,27 +132,35 @@ exporters: # # resource_attributes_as_tags: false + ## Deprecated: [0.54.0] use instrumentation_scope_metadata_as_tags instead in favor of + ## https://github.com/open-telemetry/opentelemetry-proto/releases/tag/v0.15.0 + ## Both must not be enabled at the same time. ## @param instrumentation_library_metadata_as_tags - string - optional - default: false ## Set to true to add metadata about the instrumentation library that created a metric. # # instrumentation_library_metadata_as_tags: false + ## @param instrumentation_scope_metadata_as_tags - string - optional - default: false + ## Set to true to add metadata about the instrumentation scope that created a metric. + # + # instrumentation_scope_metadata_as_tags: false + ## @param histograms - custom object - optional ## Histograms specific configuration. ## @param mode - string - optional - default: distributions ## How to report histograms. Valid values are: - ## + ## ## - `distributions` to report metrics as Datadog distributions (recommended). ## - `nobuckets` to not report bucket metrics, ## - `counters` to report one metric per histogram bucket. # # mode: distributions - + ## @param send_count_sum_metrics - boolean - optional - default: false ## Whether to report sum and count as separate histogram metrics. # # send_count_sum_metrics: false - + ## @param sums - custom object - optional ## Sums specific configuration. ## @param cumulative_monotonic_mode - string - optional - default: to_delta @@ -167,7 +175,7 @@ exporters: ## Summaries specific configuration. ## @param mode - string - optional - default: gauges ## How to report summaries. Valid values are: - ## + ## ## - `noquantiles` to not report quantile metrics ## - `gauges` to report one gauge metric per quantile. # @@ -188,7 +196,7 @@ exporters: ## A blacklist of regular expressions can be provided to disable certain traces based on their resource name ## all entries must be surrounded by double quotes and separated by commas. # - # ignore_resources: ["(GET|POST) /healthcheck"] + # ignore_resources: ["(GET|POST) /healthcheck"] ## @param span_name_remappings - map of key/value pairs - optional ## A map of Datadog span operation name keys and preferred name valuues to update those names to. This can be used to @@ -196,7 +204,7 @@ exporters: ## shorten or modify span names to something more user friendly in the case of instrumentation libraries with ## particularly verbose names. # - # span_name_remappings: + # span_name_remappings: # io.opentelemetry.javaagent.spring.client: spring.client # instrumentation:express.server: express # go.opentelemetry.io_contrib_instrumentation_net_http_otelhttp.client: http.client @@ -207,7 +215,7 @@ exporters: ## https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/1909 # # span_name_as_resource_name: true - + ## @param host_metadata - custom object - optional ## Host metadata specific configuration. ## Host metadata is the information used for populating the infrastructure list, the host map and providing host tags functionality within the Datadog app. @@ -237,7 +245,7 @@ exporters: ## @param tags - list of strings - optional - default: empty list ## List of host tags to be sent as part of the host metadata. ## These tags will be attached to telemetry signals that have the host metadata hostname. - ## + ## ## To attach tags to telemetry signals regardless of the host, use a processor instead. # # tags: [] diff --git a/exporter/datadogexporter/example/example_k8s_manifest.yaml b/exporter/datadogexporter/example/example_k8s_manifest.yaml index 258803116b6e..3a606b9e5d0e 100644 --- a/exporter/datadogexporter/example/example_k8s_manifest.yaml +++ b/exporter/datadogexporter/example/example_k8s_manifest.yaml @@ -1,5 +1,5 @@ # This manifest file is meant as an example of how to deploy otel-agent as daemonset and otel-collector as a standalone service. -# Using this example should correctly identifies hostnames for individual k8s nodes. +# Using this example should correctly identifies hostnames for individual k8s nodes. # This is meant as an example only and may differ depending on deployment scenario and specifics of the environment the collector is used. --- # The k8sattributes processor may require additional diff --git a/exporter/datadogexporter/factory.go b/exporter/datadogexporter/factory.go index 0d07d62545bb..e3ca6bd1193f 100644 --- a/exporter/datadogexporter/factory.go +++ b/exporter/datadogexporter/factory.go @@ -137,6 +137,7 @@ func (f *factory) createDefaultConfig() config.Exporter { ExporterConfig: ddconfig.MetricsExporterConfig{ ResourceAttributesAsTags: false, InstrumentationLibraryMetadataAsTags: false, + InstrumentationScopeMetadataAsTags: false, }, HistConfig: ddconfig.HistogramConfig{ Mode: "distributions", diff --git a/exporter/datadogexporter/internal/model/internal/instrumentationscope/metadata.go b/exporter/datadogexporter/internal/model/internal/instrumentationscope/metadata.go new file mode 100644 index 000000000000..2a602033867f --- /dev/null +++ b/exporter/datadogexporter/internal/model/internal/instrumentationscope/metadata.go @@ -0,0 +1,35 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package instrumentationscope // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/model/internal/instrumentationscope" + +import ( + "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/model/internal/utils" + + "go.opentelemetry.io/collector/pdata/pcommon" +) + +const ( + instrumentationScopeTag = "instrumentation_scope" + instrumentationScopeVersionTag = "instrumentation_scope_version" +) + +// TagsFromInstrumentationScopeMetadata takes the name and version of +// the instrumentation scope and converts them to Datadog tags. +func TagsFromInstrumentationScopeMetadata(il pcommon.InstrumentationScope) []string { + return []string{ + utils.FormatKeyValueTag(instrumentationScopeTag, il.Name()), + utils.FormatKeyValueTag(instrumentationScopeVersionTag, il.Version()), + } +} diff --git a/exporter/datadogexporter/internal/model/internal/instrumentationscope/metadata_test.go b/exporter/datadogexporter/internal/model/internal/instrumentationscope/metadata_test.go new file mode 100644 index 000000000000..7e6618ccfc73 --- /dev/null +++ b/exporter/datadogexporter/internal/model/internal/instrumentationscope/metadata_test.go @@ -0,0 +1,45 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package instrumentationscope + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/pcommon" +) + +func TestTagsFromInstrumentationScopeMetadata(t *testing.T) { + tests := []struct { + name string + version string + expectedTags []string + }{ + {"test-il", "1.0.0", []string{fmt.Sprintf("%s:%s", instrumentationScopeTag, "test-il"), fmt.Sprintf("%s:%s", instrumentationScopeVersionTag, "1.0.0")}}, + {"test-il", "", []string{fmt.Sprintf("%s:%s", instrumentationScopeTag, "test-il"), fmt.Sprintf("%s:%s", instrumentationScopeVersionTag, "n/a")}}, + {"", "1.0.0", []string{fmt.Sprintf("%s:%s", instrumentationScopeTag, "n/a"), fmt.Sprintf("%s:%s", instrumentationScopeVersionTag, "1.0.0")}}, + {"", "", []string{fmt.Sprintf("%s:%s", instrumentationScopeTag, "n/a"), fmt.Sprintf("%s:%s", instrumentationScopeVersionTag, "n/a")}}, + } + + for _, testInstance := range tests { + il := pcommon.NewInstrumentationScope() + il.SetName(testInstance.name) + il.SetVersion(testInstance.version) + tags := TagsFromInstrumentationScopeMetadata(il) + + assert.ElementsMatch(t, testInstance.expectedTags, tags) + } +} diff --git a/exporter/datadogexporter/internal/model/translator/config.go b/exporter/datadogexporter/internal/model/translator/config.go index aefa80c4cf5a..2b3b3cbbc7e9 100644 --- a/exporter/datadogexporter/internal/model/translator/config.go +++ b/exporter/datadogexporter/internal/model/translator/config.go @@ -22,12 +22,16 @@ import ( type translatorConfig struct { // metrics export behavior - HistMode HistogramMode - SendCountSum bool - Quantiles bool - SendMonotonic bool - ResourceAttributesAsTags bool + HistMode HistogramMode + SendCountSum bool + Quantiles bool + SendMonotonic bool + ResourceAttributesAsTags bool + // Deprecated: [0.54.0] Use InstrumentationScopeMetadataAsTags instead in favor of + // https://github.com/open-telemetry/opentelemetry-proto/releases/tag/v0.15.0 + // Both must not be enabled at the same time. InstrumentationLibraryMetadataAsTags bool + InstrumentationScopeMetadataAsTags bool // cache configuration sweepInterval int64 @@ -98,6 +102,14 @@ func WithInstrumentationLibraryMetadataAsTags() Option { } } +// WithInstrumentationScopeMetadataAsTags sets instrumentation scope metadata as tags. +func WithInstrumentationScopeMetadataAsTags() Option { + return func(t *translatorConfig) error { + t.InstrumentationScopeMetadataAsTags = true + return nil + } +} + // HistogramMode is an export mode for OTLP Histogram metrics. type HistogramMode string diff --git a/exporter/datadogexporter/internal/model/translator/metrics_translator.go b/exporter/datadogexporter/internal/model/translator/metrics_translator.go index 614df128a456..010ed3fc59c6 100644 --- a/exporter/datadogexporter/internal/model/translator/metrics_translator.go +++ b/exporter/datadogexporter/internal/model/translator/metrics_translator.go @@ -28,6 +28,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/model/attributes" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/model/internal/instrumentationlibrary" + "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/model/internal/instrumentationscope" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/model/source" ) @@ -59,6 +60,7 @@ func New(logger *zap.Logger, options ...Option) (*Translator, error) { SendMonotonic: true, ResourceAttributesAsTags: false, InstrumentationLibraryMetadataAsTags: false, + InstrumentationScopeMetadataAsTags: false, sweepInterval: 1800, deltaTTL: 3600, fallbackSourceProvider: &noSourceProvider{}, @@ -459,7 +461,9 @@ func (t *Translator) MapMetrics(ctx context.Context, md pmetric.Metrics, consume metricsArray := ilm.Metrics() var additionalTags []string - if t.cfg.InstrumentationLibraryMetadataAsTags { + if t.cfg.InstrumentationScopeMetadataAsTags { + additionalTags = append(attributeTags, instrumentationscope.TagsFromInstrumentationScopeMetadata(ilm.Scope())...) + } else if t.cfg.InstrumentationLibraryMetadataAsTags { additionalTags = append(attributeTags, instrumentationlibrary.TagsFromInstrumentationLibraryMetadata(ilm.Scope())...) } else { additionalTags = attributeTags diff --git a/exporter/datadogexporter/internal/model/translator/metrics_translator_test.go b/exporter/datadogexporter/internal/model/translator/metrics_translator_test.go index 90af001ade12..705308b70d94 100644 --- a/exporter/datadogexporter/internal/model/translator/metrics_translator_test.go +++ b/exporter/datadogexporter/internal/model/translator/metrics_translator_test.go @@ -1221,26 +1221,30 @@ func TestMapMetrics(t *testing.T) { "env:dev", } - ilName := "instrumentation_library" - ilVersion := "1.0.0" + instructionName := "foo" + instructionVersion := "1.0.0" ilTags := []string{ - fmt.Sprintf("instrumentation_library:%s", ilName), - fmt.Sprintf("instrumentation_library_version:%s", ilVersion), + fmt.Sprintf("instrumentation_library:%s", instructionName), + fmt.Sprintf("instrumentation_library_version:%s", instructionVersion), + } + isTags := []string{ + fmt.Sprintf("instrumentation_scope:%s", instructionName), + fmt.Sprintf("instrumentation_scope_version:%s", instructionVersion), } tests := []struct { - name string resourceAttributesAsTags bool instrumentationLibraryMetadataAsTags bool + instrumentationScopeMetadataAsTags bool expectedMetrics []metric expectedSketches []sketch expectedUnknownMetricType int expectedUnsupportedAggregationTemporality int }{ { - name: "ResourceAttributesAsTags: false, InstrumentationLibraryMetadataAsTags: false", resourceAttributesAsTags: false, instrumentationLibraryMetadataAsTags: false, + instrumentationScopeMetadataAsTags: false, expectedMetrics: []metric{ newGaugeWithHostname("int.gauge", 1, attrTags), newGaugeWithHostname("double.gauge", math.Pi, attrTags), @@ -1277,9 +1281,9 @@ func TestMapMetrics(t *testing.T) { expectedUnsupportedAggregationTemporality: 3, }, { - name: "ResourceAttributesAsTags: true, InstrumentationLibraryMetadataAsTags: false", resourceAttributesAsTags: true, instrumentationLibraryMetadataAsTags: false, + instrumentationScopeMetadataAsTags: false, expectedMetrics: []metric{ newGaugeWithHostname("int.gauge", 1, attrTags), newGaugeWithHostname("double.gauge", math.Pi, attrTags), @@ -1316,9 +1320,9 @@ func TestMapMetrics(t *testing.T) { expectedUnsupportedAggregationTemporality: 3, }, { - name: "ResourceAttributesAsTags: false, InstrumentationLibraryMetadataAsTags: true", resourceAttributesAsTags: false, instrumentationLibraryMetadataAsTags: true, + instrumentationScopeMetadataAsTags: false, expectedMetrics: []metric{ newGaugeWithHostname("int.gauge", 1, append(attrTags, ilTags...)), newGaugeWithHostname("double.gauge", math.Pi, append(attrTags, ilTags...)), @@ -1355,9 +1359,9 @@ func TestMapMetrics(t *testing.T) { expectedUnsupportedAggregationTemporality: 3, }, { - name: "ResourceAttributesAsTags: true, InstrumentationLibraryMetadataAsTags: true", resourceAttributesAsTags: true, instrumentationLibraryMetadataAsTags: true, + instrumentationScopeMetadataAsTags: false, expectedMetrics: []metric{ newGaugeWithHostname("int.gauge", 1, append(attrTags, ilTags...)), newGaugeWithHostname("double.gauge", math.Pi, append(attrTags, ilTags...)), @@ -1393,11 +1397,56 @@ func TestMapMetrics(t *testing.T) { expectedUnknownMetricType: 1, expectedUnsupportedAggregationTemporality: 3, }, + { + resourceAttributesAsTags: true, + instrumentationLibraryMetadataAsTags: false, + instrumentationScopeMetadataAsTags: true, + expectedMetrics: []metric{ + newGaugeWithHostname("int.gauge", 1, append(attrTags, isTags...)), + newGaugeWithHostname("double.gauge", math.Pi, append(attrTags, isTags...)), + newCountWithHostname("int.delta.sum", 2, 0, append(attrTags, isTags...)), + newCountWithHostname("double.delta.sum", math.E, 0, append(attrTags, isTags...)), + newCountWithHostname("int.delta.monotonic.sum", 2, 0, append(attrTags, isTags...)), + newCountWithHostname("double.delta.monotonic.sum", math.E, 0, append(attrTags, isTags...)), + newCountWithHostname("summary.sum", 10_000, 2, append(attrTags, isTags...)), + newCountWithHostname("summary.count", 100, 2, append(attrTags, isTags...)), + newGaugeWithHostname("int.cumulative.sum", 4, append(attrTags, isTags...)), + newGaugeWithHostname("double.cumulative.sum", 4, append(attrTags, isTags...)), + newCountWithHostname("int.cumulative.monotonic.sum", 3, 2, append(attrTags, isTags...)), + newCountWithHostname("double.cumulative.monotonic.sum", math.Pi, 2, append(attrTags, isTags...)), + }, + expectedSketches: []sketch{ + newSketchWithHostname("double.histogram", summary.Summary{ + Min: 0, + Max: 0, + Sum: math.Phi, + Avg: math.Phi / 20, + Cnt: 20, + }, append(attrTags, isTags...)), + newSketchWithHostname("double.exponentialHistogram", summary.Summary{ + // Expected min: lower bound of the highest negative bucket + Min: -math.Pow(math.Pow(2, math.Pow(2, -6)), 7), + // Expected max: upper bound of the highest positive bucket + Max: math.Pow(math.Pow(2, math.Pow(2, -6)), 5), + Sum: math.Phi, + Avg: math.Phi / 25, + Cnt: 25, + }, append(attrTags, isTags...)), + }, + expectedUnknownMetricType: 1, + expectedUnsupportedAggregationTemporality: 3, + }, } for _, testInstance := range tests { - t.Run(testInstance.name, func(t *testing.T) { - md := createTestMetrics(attrs, ilName, ilVersion) + name := fmt.Sprintf( + "ResourceAttributesAsTags: %t, InstrumentationScopeMetadataAsTags: %t, InstrumentationLibraryName: %t", + testInstance.resourceAttributesAsTags, + testInstance.instrumentationScopeMetadataAsTags, + testInstance.instrumentationLibraryMetadataAsTags, + ) + t.Run(name, func(t *testing.T) { + md := createTestMetrics(attrs, instructionName, instructionVersion) core, observed := observer.New(zapcore.DebugLevel) testLogger := zap.New(core) @@ -1408,6 +1457,9 @@ func TestMapMetrics(t *testing.T) { if testInstance.resourceAttributesAsTags { options = append(options, WithResourceAttributesAsTags()) } + if testInstance.instrumentationScopeMetadataAsTags { + options = append(options, WithInstrumentationScopeMetadataAsTags()) + } if testInstance.instrumentationLibraryMetadataAsTags { options = append(options, WithInstrumentationLibraryMetadataAsTags()) } diff --git a/exporter/datadogexporter/metrics_exporter.go b/exporter/datadogexporter/metrics_exporter.go index a178bec18eeb..f3b797e9fe22 100644 --- a/exporter/datadogexporter/metrics_exporter.go +++ b/exporter/datadogexporter/metrics_exporter.go @@ -73,7 +73,15 @@ func translatorFromConfig(logger *zap.Logger, cfg *config.Config, sourceProvider options = append(options, translator.WithResourceAttributesAsTags()) } - if cfg.Metrics.ExporterConfig.InstrumentationLibraryMetadataAsTags { + if cfg.Metrics.ExporterConfig.InstrumentationScopeMetadataAsTags && cfg.Metrics.ExporterConfig.InstrumentationLibraryMetadataAsTags { // nolint SA1019 + return nil, fmt.Errorf("cannot use both instrumentation_library_metadata_as_tags(deprecated) and instrumentation_scope_metadata_as_tags") + } + + if cfg.Metrics.ExporterConfig.InstrumentationScopeMetadataAsTags { + options = append(options, translator.WithInstrumentationScopeMetadataAsTags()) + } + + if cfg.Metrics.ExporterConfig.InstrumentationLibraryMetadataAsTags { // nolint SA1019 options = append(options, translator.WithInstrumentationLibraryMetadataAsTags()) }