From 2daa9ebc7e27ed2f8ac968e0b56a3871fa762d78 Mon Sep 17 00:00:00 2001 From: Pablo Baeyens Date: Fri, 17 May 2024 14:40:55 -0400 Subject: [PATCH] [pkg/otlp/metrics] Add WithSplatArrayAttributes --- .chloggen/mx-psi_splat-tags.yaml | 17 ++++++++++++++ .chloggen/mx-psi_splat-tags2.yaml | 17 ++++++++++++++ pkg/otlp/metrics/config.go | 9 ++++++++ pkg/otlp/metrics/dimensions.go | 17 ++++++++++---- pkg/otlp/metrics/dimensions_test.go | 23 ++++++++++++++++--- .../exponential_histograms_translator.go | 2 +- pkg/otlp/metrics/metrics_translator.go | 8 +++---- 7 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 .chloggen/mx-psi_splat-tags.yaml create mode 100644 .chloggen/mx-psi_splat-tags2.yaml diff --git a/.chloggen/mx-psi_splat-tags.yaml b/.chloggen/mx-psi_splat-tags.yaml new file mode 100644 index 00000000..c0d6095b --- /dev/null +++ b/.chloggen/mx-psi_splat-tags.yaml @@ -0,0 +1,17 @@ +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component (e.g. pkg/quantile) +component: pkg/otlp/metrics + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add `WithSplatArrayAttributes` translator option + +# The PR related to this change +issues: [329] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: | + - This option destructures an array valued attribute into multiple tags with the same key and different values. diff --git a/.chloggen/mx-psi_splat-tags2.yaml b/.chloggen/mx-psi_splat-tags2.yaml new file mode 100644 index 00000000..eae42540 --- /dev/null +++ b/.chloggen/mx-psi_splat-tags2.yaml @@ -0,0 +1,17 @@ +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: breaking + +# The name of the component (e.g. pkg/quantile) +component: pkg/otlp/metrics + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add `splat` option to `WithAttributeMap` + +# The PR related to this change +issues: [329] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: | + - This option destructures an array valued attribute into multiple tags with the same key and different values. diff --git a/pkg/otlp/metrics/config.go b/pkg/otlp/metrics/config.go index 3875bda2..51648264 100644 --- a/pkg/otlp/metrics/config.go +++ b/pkg/otlp/metrics/config.go @@ -29,6 +29,7 @@ type translatorConfig struct { InitialCumulMonoValueMode InitialCumulMonoValueMode InstrumentationLibraryMetadataAsTags bool InstrumentationScopeMetadataAsTags bool + SplatArrayAttributes bool originProduct OriginProduct @@ -215,3 +216,11 @@ func WithInitialCumulMonoValueMode(mode InitialCumulMonoValueMode) TranslatorOpt return nil } } + +// WithSplatArrayAttributes destructures an array attribute into multiple Datadog tags. +func WithSplatArrayAttributes() TranslatorOption { + return func(t *translatorConfig) error { + t.SplatArrayAttributes = true + return nil + } +} diff --git a/pkg/otlp/metrics/dimensions.go b/pkg/otlp/metrics/dimensions.go index 8187607e..3f28dccd 100644 --- a/pkg/otlp/metrics/dimensions.go +++ b/pkg/otlp/metrics/dimensions.go @@ -78,11 +78,18 @@ func (d *Dimensions) OriginProductDetail() OriginProductDetail { } // getTags maps an attributeMap into a slice of Datadog tags -func getTags(labels pcommon.Map) []string { +func getTags(labels pcommon.Map, splat bool) []string { tags := make([]string, 0, labels.Len()) labels.Range(func(key string, value pcommon.Value) bool { - v := value.AsString() - tags = append(tags, utils.FormatKeyValueTag(key, v)) + if splat && value.Type() == pcommon.ValueTypeSlice { + for i := 0; i < value.Slice().Len(); i++ { + v := value.Slice().At(i).AsString() + tags = append(tags, utils.FormatKeyValueTag(key, v)) + } + } else { + v := value.AsString() + tags = append(tags, utils.FormatKeyValueTag(key, v)) + } return true }) return tags @@ -106,8 +113,8 @@ func (d *Dimensions) AddTags(tags ...string) *Dimensions { } // WithAttributeMap creates a new metricDimensions struct with additional tags from attributes. -func (d *Dimensions) WithAttributeMap(labels pcommon.Map) *Dimensions { - return d.AddTags(getTags(labels)...) +func (d *Dimensions) WithAttributeMap(labels pcommon.Map, splat bool) *Dimensions { + return d.AddTags(getTags(labels, splat)...) } // WithSuffix creates a new dimensions struct with an extra name suffix. diff --git a/pkg/otlp/metrics/dimensions_test.go b/pkg/otlp/metrics/dimensions_test.go index e8187c40..f4b405e3 100644 --- a/pkg/otlp/metrics/dimensions_test.go +++ b/pkg/otlp/metrics/dimensions_test.go @@ -27,12 +27,29 @@ func TestWithAttributeMap(t *testing.T) { "key1": "val1", "key2": "val2", "key3": "", + "key4": []any{"val4a", "val4b"}, }) dims := Dimensions{} assert.ElementsMatch(t, - dims.WithAttributeMap(attributes).tags, - [...]string{"key1:val1", "key2:val2", "key3:n/a"}, + dims.WithAttributeMap(attributes, false).tags, + [...]string{"key1:val1", "key2:val2", "key3:n/a", `key4:["val4a","val4b"]`}, + ) +} + +func TestWithAttributeMapSplat(t *testing.T) { + attributes := pcommon.NewMap() + attributes.FromRaw(map[string]interface{}{ + "key1": "val1", + "key2": "val2", + "key3": "", + "key4": []any{"val4a", "val4b"}, + }) + + dims := Dimensions{} + assert.ElementsMatch(t, + dims.WithAttributeMap(attributes, true).tags, + [...]string{"key1:val1", "key2:val2", "key3:n/a", "key4:val4a", "key4:val4b"}, ) } @@ -115,7 +132,7 @@ func TestAllFieldsAreCopied(t *testing.T) { newDims := dims. AddTags("tagThree:c"). WithSuffix("suffix"). - WithAttributeMap(attributes) + WithAttributeMap(attributes, false) assert.Equal(t, "example.name.suffix", newDims.Name()) assert.Equal(t, "hostname", newDims.Host()) diff --git a/pkg/otlp/metrics/exponential_histograms_translator.go b/pkg/otlp/metrics/exponential_histograms_translator.go index 006610f8..ac3a5697 100644 --- a/pkg/otlp/metrics/exponential_histograms_translator.go +++ b/pkg/otlp/metrics/exponential_histograms_translator.go @@ -93,7 +93,7 @@ func (t *Translator) mapExponentialHistogramMetrics( p := slice.At(i) startTs := uint64(p.StartTimestamp()) ts := uint64(p.Timestamp()) - pointDims := dims.WithAttributeMap(p.Attributes()) + pointDims := dims.WithAttributeMap(p.Attributes(), t.cfg.SplatArrayAttributes) histInfo := histogramInfo{ok: true} diff --git a/pkg/otlp/metrics/metrics_translator.go b/pkg/otlp/metrics/metrics_translator.go index 04df435d..7f6f222c 100644 --- a/pkg/otlp/metrics/metrics_translator.go +++ b/pkg/otlp/metrics/metrics_translator.go @@ -151,7 +151,7 @@ func (t *Translator) mapNumberMetrics( for i := 0; i < slice.Len(); i++ { p := slice.At(i) - pointDims := dims.WithAttributeMap(p.Attributes()) + pointDims := dims.WithAttributeMap(p.Attributes(), t.cfg.SplatArrayAttributes) var val float64 switch p.ValueType() { case pmetric.NumberDataPointValueTypeDouble: @@ -205,7 +205,7 @@ func (t *Translator) mapNumberMonotonicMetrics( p := slice.At(i) ts := uint64(p.Timestamp()) startTs := uint64(p.StartTimestamp()) - pointDims := dims.WithAttributeMap(p.Attributes()) + pointDims := dims.WithAttributeMap(p.Attributes(), t.cfg.SplatArrayAttributes) var val float64 switch p.ValueType() { @@ -452,7 +452,7 @@ func (t *Translator) mapHistogramMetrics( p := slice.At(i) startTs := uint64(p.StartTimestamp()) ts := uint64(p.Timestamp()) - pointDims := dims.WithAttributeMap(p.Attributes()) + pointDims := dims.WithAttributeMap(p.Attributes(), t.cfg.SplatArrayAttributes) histInfo := histogramInfo{ok: true} @@ -556,7 +556,7 @@ func (t *Translator) mapSummaryMetrics( p := slice.At(i) startTs := uint64(p.StartTimestamp()) ts := uint64(p.Timestamp()) - pointDims := dims.WithAttributeMap(p.Attributes()) + pointDims := dims.WithAttributeMap(p.Attributes(), t.cfg.SplatArrayAttributes) // count and sum are increasing; we treat them as cumulative monotonic sums. {