diff --git a/pkg/backends/otlp/backend.go b/pkg/backends/otlp/backend.go index f165da27..48a12b5d 100644 --- a/pkg/backends/otlp/backend.go +++ b/pkg/backends/otlp/backend.go @@ -146,6 +146,9 @@ func (bd *Backend) SendMetricsAsync(ctx context.Context, mm *gostatsd.MetricMap, mm.Counters.Each(func(name, _ string, cm gostatsd.Counter) { resources, attributes := data.SplitMetricTagsByKeysAndConvert(cm.Tags, bd.resourceKeys) + if cm.Source != "" { + attributes.Insert("source", string(cm.Source)) + } rate := data.NewMetric(name).SetGauge( data.NewGauge( @@ -173,6 +176,9 @@ func (bd *Backend) SendMetricsAsync(ctx context.Context, mm *gostatsd.MetricMap, mm.Gauges.Each(func(name, _ string, gm gostatsd.Gauge) { resources, attributes := data.SplitMetricTagsByKeysAndConvert(gm.Tags, bd.resourceKeys) + if gm.Source != "" { + attributes.Insert("source", string(gm.Source)) + } m := data.NewMetric(name).SetGauge( data.NewGauge( @@ -189,6 +195,9 @@ func (bd *Backend) SendMetricsAsync(ctx context.Context, mm *gostatsd.MetricMap, mm.Sets.Each(func(name, _ string, sm gostatsd.Set) { resources, attributes := data.SplitMetricTagsByKeysAndConvert(sm.Tags, bd.resourceKeys) + if sm.Source != "" { + attributes.Insert("source", string(sm.Source)) + } m := data.NewMetric(name).SetGauge( data.NewGauge( @@ -205,6 +214,9 @@ func (bd *Backend) SendMetricsAsync(ctx context.Context, mm *gostatsd.MetricMap, mm.Timers.Each(func(name, _ string, t gostatsd.Timer) { resources, attributes := data.SplitMetricTagsByKeysAndConvert(t.Tags, bd.resourceKeys) + if t.Source != "" { + attributes.Insert("source", string(t.Source)) + } switch bd.convertTimersToGauges { case true: diff --git a/pkg/backends/otlp/backend_test.go b/pkg/backends/otlp/backend_test.go index 5c92dab8..74709bce 100644 --- a/pkg/backends/otlp/backend_test.go +++ b/pkg/backends/otlp/backend_test.go @@ -299,6 +299,91 @@ func TestBackendSendAsyncMetrics(t *testing.T) { } }, }, + { + name: "valid metric data with source", + mm: func() *gostatsd.MetricMap { + mm := gostatsd.NewMetricMap(false) + mm.Receive(&gostatsd.Metric{ + Name: "my-metric", + Value: 100.0, + Rate: 1, + Tags: gostatsd.Tags{"service.name:my-awesome-service"}, + Timestamp: gostatsd.Nanotime(time.Unix(100, 0).UnixNano()), + Type: gostatsd.COUNTER, + Source: "fake-source", + }) + return mm + }(), + handler: func(w http.ResponseWriter, r *http.Request) { + body, err := io.ReadAll(r.Body) + assert.NoError(t, err, "Must not error reading body") + assert.NotEmpty(t, body, "Must not have an empty body") + + req := &v1export.ExportMetricsServiceRequest{} + err = proto.Unmarshal(body, req) + assert.NoError(t, err, "Must not error unmarshalling body") + + ms := req.GetResourceMetrics()[0].GetScopeMetrics()[0].GetMetrics() + dpCountAttrs := ms[1].GetSum().DataPoints[0].GetAttributes() + for _, attr := range dpCountAttrs { + if attr.Key == "source" { + assert.Equal(t, "fake-source", attr.Value.GetStringValue()) + return + } + + assert.Error(t, fmt.Errorf("source attribute not found")) + } + }, + enableHistograms: false, + validate: func(t *testing.T) func(errs []error) { + return func(errs []error) { + if !assert.Len(t, errs, 0, "Must not error") { + return + } + } + }, + }, + { + name: "valid metric data without source", + mm: func() *gostatsd.MetricMap { + mm := gostatsd.NewMetricMap(false) + mm.Receive(&gostatsd.Metric{ + Name: "my-metric", + Value: 100.0, + Rate: 1, + Tags: gostatsd.Tags{"service.name:my-awesome-service"}, + Timestamp: gostatsd.Nanotime(time.Unix(100, 0).UnixNano()), + Type: gostatsd.COUNTER, + }) + return mm + }(), + handler: func(w http.ResponseWriter, r *http.Request) { + body, err := io.ReadAll(r.Body) + assert.NoError(t, err, "Must not error reading body") + assert.NotEmpty(t, body, "Must not have an empty body") + + req := &v1export.ExportMetricsServiceRequest{} + err = proto.Unmarshal(body, req) + assert.NoError(t, err, "Must not error unmarshalling body") + + ms := req.GetResourceMetrics()[0].GetScopeMetrics()[0].GetMetrics() + dpCountAttrs := ms[1].GetSum().DataPoints[0].GetAttributes() + for _, attr := range dpCountAttrs { + if attr.Key == "source" { + assert.Error(t, fmt.Errorf("source attribute not found")) + return + } + } + }, + enableHistograms: false, + validate: func(t *testing.T) func(errs []error) { + return func(errs []error) { + if !assert.Len(t, errs, 0, "Must not error") { + return + } + } + }, + }, { name: "valid metric data with histogram conversion", mm: func() *gostatsd.MetricMap {