From 414cfa1b46dec1a62b44f645978a51e49feb7ffb Mon Sep 17 00:00:00 2001 From: Jay Vercellone Date: Tue, 27 Feb 2024 13:20:08 -0800 Subject: [PATCH] Support latest DogStatsD version (#31296) **Description:** * Support DogStatsD v1.2 by accepting metrics with container IDs * Support DogStatsD v1.3 by accepting metrics with timestamps * Add tests for the cases above * Improve readability in `statsd_parser_test.go` when calling `testStatsDMetric` * Add changelog entry **Link to tracking Issue:** #31295 **Testing:** 1. Added unit tests to validate that the new fields are accepted and interpreted correctly 2. Manual tests to verify that the metrics go through a collector pipeline. Notice the `container_id` attribute and the `Timestamp` field, which contains a custom value different from `StartTimestamp`: ``` ScopeMetrics #0 ScopeMetrics SchemaURL: InstrumentationScope otelcol/statsdreceiver 0.94.0-dev Metric #0 Descriptor: -> Name: workflow_execution.failure -> Description: -> Unit: -> DataType: Sum -> IsMonotonic: false -> AggregationTemporality: Delta NumberDataPoints #0 Data point attributes: -> container_id: Str(d69b8773f0ac1d93447a5835cb4ed1bf13dd336d32994830687ae1f352c86fe4) -> deployment.id: Str(d_0lBskd) -> metric_type: Str(counter) -> env: Str(development) -> project.id: Str(proj_kYRs18) -> trace.id: Str(2cQtSfsef2TN3EC2psGIorPaFd8) -> workflow.id: Str(p_0PACqQ) StartTimestamp: 2024-02-16 03:53:30.323425523 +0000 UTC Timestamp: 2024-02-16 03:53:51 +0000 UTC Value: 1 ``` --- .chloggen/feat_support-latest-dogstatsd.yaml | 27 + receiver/statsdreceiver/go.mod | 1 + .../internal/protocol/metric_translator.go | 9 +- .../internal/protocol/statsd_parser.go | 24 + .../internal/protocol/statsd_parser_test.go | 584 +++++++++++++++--- 5 files changed, 575 insertions(+), 70 deletions(-) create mode 100755 .chloggen/feat_support-latest-dogstatsd.yaml diff --git a/.chloggen/feat_support-latest-dogstatsd.yaml b/.chloggen/feat_support-latest-dogstatsd.yaml new file mode 100755 index 000000000000..3a49cc43a682 --- /dev/null +++ b/.chloggen/feat_support-latest-dogstatsd.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: statsdreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add support for the latest version of DogStatsD protocol (v1.3) + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [31295] + +# (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: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [user] diff --git a/receiver/statsdreceiver/go.mod b/receiver/statsdreceiver/go.mod index 939d859b0e7d..eaa16fb60ee6 100644 --- a/receiver/statsdreceiver/go.mod +++ b/receiver/statsdreceiver/go.mod @@ -14,6 +14,7 @@ require ( go.opentelemetry.io/collector/consumer v0.95.0 go.opentelemetry.io/collector/pdata v1.2.0 go.opentelemetry.io/collector/receiver v0.95.0 + go.opentelemetry.io/collector/semconv v0.95.0 go.opentelemetry.io/otel v1.23.1 go.opentelemetry.io/otel/metric v1.23.1 go.opentelemetry.io/otel/trace v1.23.1 diff --git a/receiver/statsdreceiver/internal/protocol/metric_translator.go b/receiver/statsdreceiver/internal/protocol/metric_translator.go index 9dc7e7573d9f..cd79d10e34db 100644 --- a/receiver/statsdreceiver/internal/protocol/metric_translator.go +++ b/receiver/statsdreceiver/internal/protocol/metric_translator.go @@ -34,13 +34,20 @@ func buildCounterMetric(parsedMetric statsDMetric, isMonotonicCounter bool) pmet dp.Attributes().PutStr(string(i.Attribute().Key), i.Attribute().Value.AsString()) } + if parsedMetric.timestamp != 0 { + dp.SetTimestamp(pcommon.Timestamp(parsedMetric.timestamp)) + } + return ilm } func setTimestampsForCounterMetric(ilm pmetric.ScopeMetrics, startTime, timeNow time.Time) { dp := ilm.Metrics().At(0).Sum().DataPoints().At(0) dp.SetStartTimestamp(pcommon.NewTimestampFromTime(startTime)) - dp.SetTimestamp(pcommon.NewTimestampFromTime(timeNow)) + + if dp.Timestamp() == 0 { + dp.SetTimestamp(pcommon.NewTimestampFromTime(timeNow)) + } } func buildGaugeMetric(parsedMetric statsDMetric, timeNow time.Time) pmetric.ScopeMetrics { diff --git a/receiver/statsdreceiver/internal/protocol/statsd_parser.go b/receiver/statsdreceiver/internal/protocol/statsd_parser.go index 474fe03945ba..ccbcdd6d108a 100644 --- a/receiver/statsdreceiver/internal/protocol/statsd_parser.go +++ b/receiver/statsdreceiver/internal/protocol/statsd_parser.go @@ -16,6 +16,7 @@ import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" + semconv "go.opentelemetry.io/collector/semconv/v1.22.0" "go.opentelemetry.io/otel/attribute" ) @@ -128,6 +129,7 @@ type statsDMetric struct { addition bool unit string sampleRate float64 + timestamp uint64 } type statsDMetricDescription struct { @@ -430,6 +432,28 @@ func parseMessageToMetric(line string, enableMetricType bool, enableSimpleTags b kvs = append(kvs, attribute.String(k, v)) } + case strings.HasPrefix(part, "c:"): + // As per DogStatD protocol v1.2: + // https://docs.datadoghq.com/developers/dogstatsd/datagram_shell/?tab=metrics#dogstatsd-protocol-v12 + containerID := strings.TrimPrefix(part, "c:") + + if containerID != "" { + kvs = append(kvs, attribute.String(semconv.AttributeContainerID, containerID)) + } + case strings.HasPrefix(part, "T"): + // As per DogStatD protocol v1.3: + // https://docs.datadoghq.com/developers/dogstatsd/datagram_shell/?tab=metrics#dogstatsd-protocol-v13 + if inType != CounterType && inType != GaugeType { + return result, fmt.Errorf("only GAUGE and COUNT metrics support a timestamp") + } + + timestampStr := strings.TrimPrefix(part, "T") + timestampSeconds, err := strconv.ParseUint(timestampStr, 10, 64) + if err != nil { + return result, fmt.Errorf("invalid timestamp: %s", timestampStr) + } + + result.timestamp = timestampSeconds * 1e9 // Convert seconds to nanoseconds default: return result, fmt.Errorf("unrecognized message part: %s", part) } diff --git a/receiver/statsdreceiver/internal/protocol/statsd_parser_test.go b/receiver/statsdreceiver/internal/protocol/statsd_parser_test.go index d91ee7c3ed27..d37b8579aba6 100644 --- a/receiver/statsdreceiver/internal/protocol/statsd_parser_test.go +++ b/receiver/statsdreceiver/internal/protocol/statsd_parser_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pmetric" + semconv "go.opentelemetry.io/collector/semconv/v1.22.0" "go.opentelemetry.io/otel/attribute" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/metricstestutil" @@ -68,7 +69,7 @@ func Test_ParseMessageToMetric(t *testing.T) { "test.metric", 42, false, - "c", 0, nil, nil), + "c", 0, nil, nil, 0), }, { name: "integer counter", @@ -77,7 +78,7 @@ func Test_ParseMessageToMetric(t *testing.T) { "test.metric", 42, false, - "c", 0, nil, nil), + "c", 0, nil, nil, 0), }, { name: "invalid counter metric value", @@ -99,7 +100,37 @@ func Test_ParseMessageToMetric(t *testing.T) { "c", 0.1, []string{"key"}, - []string{"value"}), + []string{"value"}, + 0, + ), + }, + { + name: "counter metric with container ID", + input: "test.metric:42|c|#key:value|c:abc123", + wantMetric: testStatsDMetric( + "test.metric", + 42, + false, + "c", + 0, + []string{"key", semconv.AttributeContainerID}, + []string{"value", "abc123"}, + 0, + ), + }, + { + name: "counter metric with timestamp", + input: "test.metric:42|c|T1656581400", + wantMetric: testStatsDMetric( + "test.metric", + 42, + false, + "c", + 0, + nil, + nil, + 1656581400000000000, // Transformed to nanoseconds + ), }, { name: "counter metric with sample rate(not divisible) and tag", @@ -111,7 +142,9 @@ func Test_ParseMessageToMetric(t *testing.T) { "c", 0.8, []string{"key"}, - []string{"value"}), + []string{"value"}, + 0, + ), }, { name: "counter metric with sample rate(not divisible) and two tags", @@ -123,7 +156,9 @@ func Test_ParseMessageToMetric(t *testing.T) { "c", 0.8, []string{"key", "key2"}, - []string{"value", "value2"}), + []string{"value", "value2"}, + 0, + ), }, { name: "double gauge", @@ -132,7 +167,7 @@ func Test_ParseMessageToMetric(t *testing.T) { "test.metric", 42, false, - "g", 0, nil, nil), + "g", 0, nil, nil, 0), }, { name: "int gauge", @@ -141,7 +176,7 @@ func Test_ParseMessageToMetric(t *testing.T) { "test.metric", 42, false, - "g", 0, nil, nil), + "g", 0, nil, nil, 0), }, { name: "invalid gauge metric value", @@ -158,7 +193,9 @@ func Test_ParseMessageToMetric(t *testing.T) { "g", 0.1, []string{"key"}, - []string{"value"}), + []string{"value"}, + 0, + ), }, { name: "gauge metric with sample rate and two tags", @@ -170,7 +207,23 @@ func Test_ParseMessageToMetric(t *testing.T) { "g", 0.8, []string{"key", "key2"}, - []string{"value", "value2"}), + []string{"value", "value2"}, + 0, + ), + }, + { + name: "gauge metric with timestamp", + input: "test.metric:11|g|T1656581400", + wantMetric: testStatsDMetric( + "test.metric", + 11, + false, + "g", + 0, + nil, + nil, + 1656581400000000000, // Transformed to nanoseconds + ), }, { name: "double gauge plus", @@ -179,7 +232,7 @@ func Test_ParseMessageToMetric(t *testing.T) { "test.metric", 42, true, - "g", 0, nil, nil), + "g", 0, nil, nil, 0), }, { name: "double gauge minus", @@ -188,7 +241,7 @@ func Test_ParseMessageToMetric(t *testing.T) { "test.metric", -42, true, - "g", 0, nil, nil), + "g", 0, nil, nil, 0), }, { name: "int gauge plus", @@ -197,7 +250,7 @@ func Test_ParseMessageToMetric(t *testing.T) { "test.metric", 42, true, - "g", 0, nil, nil), + "g", 0, nil, nil, 0), }, { name: "int gauge minus", @@ -206,13 +259,18 @@ func Test_ParseMessageToMetric(t *testing.T) { "test.metric", -42, true, - "g", 0, nil, nil), + "g", 0, nil, nil, 0), }, { name: "invalid histogram metric value", input: "test.metric:42.abc|h", err: errors.New("parse metric value string: 42.abc"), }, + { + name: "invalid histogram with timestamp", + input: "test.metric:42|h|T1656581400", + err: errors.New("only GAUGE and COUNT metrics support a timestamp"), + }, { name: "int timer", input: "test.metric:-42|ms", @@ -220,7 +278,7 @@ func Test_ParseMessageToMetric(t *testing.T) { "test.metric", -42, true, - "ms", 0, nil, nil), + "ms", 0, nil, nil, 0), }, { name: "int histogram", @@ -229,7 +287,7 @@ func Test_ParseMessageToMetric(t *testing.T) { "test.metric", 42, false, - "h", 0, nil, nil), + "h", 0, nil, nil, 0), }, } @@ -263,7 +321,9 @@ func Test_ParseMessageToMetricWithMetricType(t *testing.T) { false, "c", 0, []string{"metric_type"}, - []string{"counter"}), + []string{"counter"}, + 0, + ), }, { name: "counter metric with sample rate and tag", @@ -275,7 +335,9 @@ func Test_ParseMessageToMetricWithMetricType(t *testing.T) { "c", 0.1, []string{"key", "metric_type"}, - []string{"value", "counter"}), + []string{"value", "counter"}, + 0, + ), }, { name: "counter metric with sample rate(not divisible) and tag", @@ -287,7 +349,9 @@ func Test_ParseMessageToMetricWithMetricType(t *testing.T) { "c", 0.8, []string{"key", "metric_type"}, - []string{"value", "counter"}), + []string{"value", "counter"}, + 0, + ), }, { name: "counter metric with sample rate(not divisible) and two tags", @@ -299,7 +363,9 @@ func Test_ParseMessageToMetricWithMetricType(t *testing.T) { "c", 0.8, []string{"key", "key2", "metric_type"}, - []string{"value", "value2", "counter"}), + []string{"value", "value2", "counter"}, + 0, + ), }, { name: "double gauge", @@ -310,7 +376,9 @@ func Test_ParseMessageToMetricWithMetricType(t *testing.T) { false, "g", 0, []string{"metric_type"}, - []string{"gauge"}), + []string{"gauge"}, + 0, + ), }, { name: "int gauge", @@ -321,7 +389,9 @@ func Test_ParseMessageToMetricWithMetricType(t *testing.T) { false, "g", 0, []string{"metric_type"}, - []string{"gauge"}), + []string{"gauge"}, + 0, + ), }, { name: "invalid gauge metric value", @@ -338,7 +408,9 @@ func Test_ParseMessageToMetricWithMetricType(t *testing.T) { "g", 0.1, []string{"key", "metric_type"}, - []string{"value", "gauge"}), + []string{"value", "gauge"}, + 0, + ), }, { name: "gauge metric with sample rate and two tags", @@ -350,7 +422,9 @@ func Test_ParseMessageToMetricWithMetricType(t *testing.T) { "g", 0.8, []string{"key", "key2", "metric_type"}, - []string{"value", "value2", "gauge"}), + []string{"value", "value2", "gauge"}, + 0, + ), }, { name: "double gauge plus", @@ -361,7 +435,9 @@ func Test_ParseMessageToMetricWithMetricType(t *testing.T) { true, "g", 0, []string{"metric_type"}, - []string{"gauge"}), + []string{"gauge"}, + 0, + ), }, { name: "double gauge minus", @@ -372,7 +448,9 @@ func Test_ParseMessageToMetricWithMetricType(t *testing.T) { true, "g", 0, []string{"metric_type"}, - []string{"gauge"}), + []string{"gauge"}, + 0, + ), }, { name: "int gauge plus", @@ -383,7 +461,9 @@ func Test_ParseMessageToMetricWithMetricType(t *testing.T) { true, "g", 0, []string{"metric_type"}, - []string{"gauge"}), + []string{"gauge"}, + 0, + ), }, { name: "int gauge minus", @@ -394,7 +474,9 @@ func Test_ParseMessageToMetricWithMetricType(t *testing.T) { true, "g", 0, []string{"metric_type"}, - []string{"gauge"}), + []string{"gauge"}, + 0, + ), }, { name: "int timer", @@ -405,7 +487,9 @@ func Test_ParseMessageToMetricWithMetricType(t *testing.T) { true, "ms", 0, []string{"metric_type"}, - []string{"timing"}), + []string{"timing"}, + 0, + ), }, { name: "int histogram", @@ -416,7 +500,9 @@ func Test_ParseMessageToMetricWithMetricType(t *testing.T) { false, "h", 0, []string{"metric_type"}, - []string{"histogram"}), + []string{"histogram"}, + 0, + ), }, { name: "int distribution", @@ -427,7 +513,9 @@ func Test_ParseMessageToMetricWithMetricType(t *testing.T) { false, "d", 0, []string{"metric_type"}, - []string{"distribution"}), + []string{"distribution"}, + 0, + ), }, } @@ -462,7 +550,9 @@ func Test_ParseMessageToMetricWithSimpleTags(t *testing.T) { "c", 0.1, []string{"key"}, - []string{"value"}), + []string{"value"}, + 0, + ), }, { name: "counter metric with sample rate and (simple) tag", @@ -474,7 +564,9 @@ func Test_ParseMessageToMetricWithSimpleTags(t *testing.T) { "c", 0.1, []string{"key"}, - []string{""}), + []string{""}, + 0, + ), }, { name: "counter metric with sample rate and two (simple) tags", @@ -486,7 +578,9 @@ func Test_ParseMessageToMetricWithSimpleTags(t *testing.T) { "c", 0.1, []string{"key", "key2"}, - []string{"", ""}), + []string{"", ""}, + 0, + ), }, } @@ -508,7 +602,7 @@ func testStatsDMetric( name string, asFloat float64, addition bool, metricType MetricType, sampleRate float64, labelKeys []string, - labelValue []string, + labelValue []string, timestamp uint64, ) statsDMetric { if len(labelKeys) > 0 { var kvs []attribute.KeyValue @@ -526,6 +620,7 @@ func testStatsDMetric( addition: addition, unit: "", sampleRate: sampleRate, + timestamp: timestamp, } } return statsDMetric{ @@ -537,6 +632,7 @@ func testStatsDMetric( addition: addition, unit: "", sampleRate: sampleRate, + timestamp: timestamp, } } @@ -593,9 +689,29 @@ func TestStatsDParser_Aggregate(t *testing.T) { }, expectedGauges: map[statsDMetricDescription]pmetric.ScopeMetrics{ testDescription("statsdTestMetric1", "g", - []string{"mykey"}, []string{"myvalue"}): buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 10102, false, "g", 0, []string{"mykey"}, []string{"myvalue"}), time.Unix(711, 0)), + []string{"mykey"}, []string{"myvalue"}): buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 10102, + false, + "g", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), time.Unix(711, 0)), testDescription("statsdTestMetric2", "g", - []string{"mykey"}, []string{"myvalue"}): buildGaugeMetric(testStatsDMetric("statsdTestMetric2", 507, false, "g", 0, []string{"mykey"}, []string{"myvalue"}), time.Unix(711, 0)), + []string{"mykey"}, []string{"myvalue"}): buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric2", + 507, + false, + "g", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), time.Unix(711, 0)), }, expectedCounters: map[statsDMetricDescription]pmetric.ScopeMetrics{}, }, @@ -615,9 +731,29 @@ func TestStatsDParser_Aggregate(t *testing.T) { }, expectedGauges: map[statsDMetricDescription]pmetric.ScopeMetrics{ testDescription("statsdTestMetric1", "g", - []string{"mykey"}, []string{"myvalue"}): buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 4885, false, "g", 0, []string{"mykey"}, []string{"myvalue"}), time.Unix(711, 0)), + []string{"mykey"}, []string{"myvalue"}): buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 4885, + false, + "g", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), time.Unix(711, 0)), testDescription("statsdTestMetric2", "g", - []string{"mykey"}, []string{"myvalue"}): buildGaugeMetric(testStatsDMetric("statsdTestMetric2", 5, false, "g", 0, []string{"mykey"}, []string{"myvalue"}), time.Unix(711, 0)), + []string{"mykey"}, []string{"myvalue"}): buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric2", + 5, + false, + "g", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), time.Unix(711, 0)), }, expectedCounters: map[statsDMetricDescription]pmetric.ScopeMetrics{}, }, @@ -637,9 +773,29 @@ func TestStatsDParser_Aggregate(t *testing.T) { }, expectedGauges: map[statsDMetricDescription]pmetric.ScopeMetrics{ testDescription("statsdTestMetric1", "g", - []string{"mykey"}, []string{"myvalue"}): buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 4101, false, "g", 0, []string{"mykey"}, []string{"myvalue"}), time.Unix(711, 0)), + []string{"mykey"}, []string{"myvalue"}): buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 4101, + false, + "g", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), time.Unix(711, 0)), testDescription("statsdTestMetric2", "g", - []string{"mykey"}, []string{"myvalue"}): buildGaugeMetric(testStatsDMetric("statsdTestMetric2", 200, false, "g", 0, []string{"mykey"}, []string{"myvalue"}), time.Unix(711, 0)), + []string{"mykey"}, []string{"myvalue"}): buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric2", + 200, + false, + "g", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), time.Unix(711, 0)), }, expectedCounters: map[statsDMetricDescription]pmetric.ScopeMetrics{}, }, @@ -654,9 +810,29 @@ func TestStatsDParser_Aggregate(t *testing.T) { expectedGauges: map[statsDMetricDescription]pmetric.ScopeMetrics{}, expectedCounters: map[statsDMetricDescription]pmetric.ScopeMetrics{ testDescription("statsdTestMetric1", "c", - []string{"mykey"}, []string{"myvalue"}): buildCounterMetric(testStatsDMetric("statsdTestMetric1", 7000, false, "c", 0, []string{"mykey"}, []string{"myvalue"}), false), + []string{"mykey"}, []string{"myvalue"}): buildCounterMetric( + testStatsDMetric( + "statsdTestMetric1", + 7000, + false, + "c", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), false), testDescription("statsdTestMetric2", "c", - []string{"mykey"}, []string{"myvalue"}): buildCounterMetric(testStatsDMetric("statsdTestMetric2", 50, false, "c", 0, []string{"mykey"}, []string{"myvalue"}), false), + []string{"mykey"}, []string{"myvalue"}): buildCounterMetric( + testStatsDMetric( + "statsdTestMetric2", + 50, + false, + "c", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), false), }, }, { @@ -674,13 +850,43 @@ func TestStatsDParser_Aggregate(t *testing.T) { }, expectedGauges: map[statsDMetricDescription]pmetric.ScopeMetrics{ testDescription("statsdTestMetric1", "g", - []string{"mykey"}, []string{"myvalue"}): buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 421, false, "g", 0, []string{"mykey"}, []string{"myvalue"}), time.Unix(711, 0)), + []string{"mykey"}, []string{"myvalue"}): buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 421, + false, + "g", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), time.Unix(711, 0)), }, expectedCounters: map[statsDMetricDescription]pmetric.ScopeMetrics{ testDescription("statsdTestMetric1", "c", - []string{"mykey"}, []string{"myvalue"}): buildCounterMetric(testStatsDMetric("statsdTestMetric1", 7000, false, "c", 0, []string{"mykey"}, []string{"myvalue"}), false), + []string{"mykey"}, []string{"myvalue"}): buildCounterMetric( + testStatsDMetric( + "statsdTestMetric1", + 7000, + false, + "c", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), false), testDescription("statsdTestMetric2", "c", - []string{"mykey"}, []string{"myvalue"}): buildCounterMetric(testStatsDMetric("statsdTestMetric2", 50, false, "c", 0, []string{"mykey"}, []string{"myvalue"}), false), + []string{"mykey"}, []string{"myvalue"}): buildCounterMetric( + testStatsDMetric( + "statsdTestMetric2", + 50, + false, + "c", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), false), }, }, { @@ -699,15 +905,55 @@ func TestStatsDParser_Aggregate(t *testing.T) { }, expectedGauges: map[statsDMetricDescription]pmetric.ScopeMetrics{ testDescription("statsdTestMetric1", "g", - []string{"mykey"}, []string{"myvalue"}): buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 319, false, "g", 0, []string{"mykey"}, []string{"myvalue"}), time.Unix(711, 0)), + []string{"mykey"}, []string{"myvalue"}): buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 319, + false, + "g", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), time.Unix(711, 0)), testDescription("statsdTestMetric1", "g", - []string{"mykey"}, []string{"myvalue1"}): buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 399, false, "g", 0, []string{"mykey"}, []string{"myvalue1"}), time.Unix(711, 0)), + []string{"mykey"}, []string{"myvalue1"}): buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 399, + false, + "g", + 0, + []string{"mykey"}, + []string{"myvalue1"}, + 0, + ), time.Unix(711, 0)), }, expectedCounters: map[statsDMetricDescription]pmetric.ScopeMetrics{ testDescription("statsdTestMetric1", "c", - []string{"mykey"}, []string{"myvalue"}): buildCounterMetric(testStatsDMetric("statsdTestMetric1", 215, false, "c", 0, []string{"mykey"}, []string{"myvalue"}), false), + []string{"mykey"}, []string{"myvalue"}): buildCounterMetric( + testStatsDMetric( + "statsdTestMetric1", + 215, + false, + "c", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), false), testDescription("statsdTestMetric2", "c", - []string{"mykey"}, []string{"myvalue"}): buildCounterMetric(testStatsDMetric("statsdTestMetric2", 75, false, "c", 0, []string{"mykey"}, []string{"myvalue"}), false), + []string{"mykey"}, []string{"myvalue"}): buildCounterMetric( + testStatsDMetric( + "statsdTestMetric2", + 75, + false, + "c", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), false), }, }, { @@ -723,12 +969,72 @@ func TestStatsDParser_Aggregate(t *testing.T) { expectedGauges: map[statsDMetricDescription]pmetric.ScopeMetrics{}, expectedCounters: map[statsDMetricDescription]pmetric.ScopeMetrics{}, expectedTimer: []pmetric.ScopeMetrics{ - buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 500, false, "ms", 0, []string{"mykey"}, []string{"myvalue"}), time.Unix(711, 0)), - buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 400, false, "h", 0, []string{"mykey"}, []string{"myvalue"}), time.Unix(711, 0)), - buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 300, false, "ms", 0, []string{"mykey"}, []string{"myvalue"}), time.Unix(711, 0)), - buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 10, false, "h", 0, []string{"mykey"}, []string{"myvalue"}), time.Unix(711, 0)), - buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 100, false, "d", 0, []string{"mykey"}, []string{"myvalue"}), time.Unix(711, 0)), - buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 200, false, "d", 0, []string{"mykey"}, []string{"myvalue"}), time.Unix(711, 0)), + buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 500, + false, + "ms", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), time.Unix(711, 0)), + buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 400, + false, + "h", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), time.Unix(711, 0)), + buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 300, + false, + "ms", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), time.Unix(711, 0)), + buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 10, + false, + "h", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), time.Unix(711, 0)), + buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 100, + false, + "d", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), time.Unix(711, 0)), + buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 200, + false, + "d", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), time.Unix(711, 0)), }, }, } @@ -789,15 +1095,55 @@ func TestStatsDParser_AggregateByAddress(t *testing.T) { expectedGauges: []map[statsDMetricDescription]pmetric.ScopeMetrics{ { testDescription("statsdTestMetric1", "g", - []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}): buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 10102, false, "g", 0, []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}), time.Unix(711, 0)), + []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}): buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 10102, + false, + "g", + 0, + []string{"mykey", "metric_type"}, + []string{"myvalue", "gauge"}, + 0, + ), time.Unix(711, 0)), testDescription("statsdTestMetric2", "g", - []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}): buildGaugeMetric(testStatsDMetric("statsdTestMetric2", 507, false, "g", 0, []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}), time.Unix(711, 0)), + []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}): buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric2", + 507, + false, + "g", + 0, + []string{"mykey", "metric_type"}, + []string{"myvalue", "gauge"}, + 0, + ), time.Unix(711, 0)), }, { testDescription("statsdTestMetric1", "g", - []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}): buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 10102, false, "g", 0, []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}), time.Unix(711, 0)), + []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}): buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 10102, + false, + "g", + 0, + []string{"mykey", "metric_type"}, + []string{"myvalue", "gauge"}, + 0, + ), time.Unix(711, 0)), testDescription("statsdTestMetric2", "g", - []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}): buildGaugeMetric(testStatsDMetric("statsdTestMetric2", 507, false, "g", 0, []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}), time.Unix(711, 0)), + []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}): buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric2", + 507, + false, + "g", + 0, + []string{"mykey", "metric_type"}, + []string{"myvalue", "gauge"}, + 0, + ), time.Unix(711, 0)), }, }, }, @@ -845,9 +1191,29 @@ func TestStatsDParser_AggregateWithMetricType(t *testing.T) { }, expectedGauges: map[statsDMetricDescription]pmetric.ScopeMetrics{ testDescription("statsdTestMetric1", "g", - []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}): buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 10102, false, "g", 0, []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}), time.Unix(711, 0)), + []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}): buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 10102, + false, + "g", + 0, + []string{"mykey", "metric_type"}, + []string{"myvalue", "gauge"}, + 0, + ), time.Unix(711, 0)), testDescription("statsdTestMetric2", "g", - []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}): buildGaugeMetric(testStatsDMetric("statsdTestMetric2", 507, false, "g", 0, []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}), time.Unix(711, 0)), + []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}): buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric2", + 507, + false, + "g", + 0, + []string{"mykey", "metric_type"}, + []string{"myvalue", "gauge"}, + 0, + ), time.Unix(711, 0)), }, expectedCounters: map[statsDMetricDescription]pmetric.ScopeMetrics{}, }, @@ -863,9 +1229,29 @@ func TestStatsDParser_AggregateWithMetricType(t *testing.T) { expectedGauges: map[statsDMetricDescription]pmetric.ScopeMetrics{}, expectedCounters: map[statsDMetricDescription]pmetric.ScopeMetrics{ testDescription("statsdTestMetric1", "c", - []string{"mykey", "metric_type"}, []string{"myvalue", "counter"}): buildCounterMetric(testStatsDMetric("statsdTestMetric1", 7000, false, "c", 0, []string{"mykey", "metric_type"}, []string{"myvalue", "counter"}), false), + []string{"mykey", "metric_type"}, []string{"myvalue", "counter"}): buildCounterMetric( + testStatsDMetric( + "statsdTestMetric1", + 7000, + false, + "c", + 0, + []string{"mykey", "metric_type"}, + []string{"myvalue", "counter"}, + 0, + ), false), testDescription("statsdTestMetric2", "c", - []string{"mykey", "metric_type"}, []string{"myvalue", "counter"}): buildCounterMetric(testStatsDMetric("statsdTestMetric2", 50, false, "c", 0, []string{"mykey", "metric_type"}, []string{"myvalue", "counter"}), false), + []string{"mykey", "metric_type"}, []string{"myvalue", "counter"}): buildCounterMetric( + testStatsDMetric( + "statsdTestMetric2", + 50, + false, + "c", + 0, + []string{"mykey", "metric_type"}, + []string{"myvalue", "counter"}, + 0, + ), false), }, }, } @@ -913,9 +1299,29 @@ func TestStatsDParser_AggregateWithIsMonotonicCounter(t *testing.T) { expectedGauges: map[statsDMetricDescription]pmetric.ScopeMetrics{}, expectedCounters: map[statsDMetricDescription]pmetric.ScopeMetrics{ testDescription("statsdTestMetric1", "c", - []string{"mykey"}, []string{"myvalue"}): buildCounterMetric(testStatsDMetric("statsdTestMetric1", 7000, false, "c", 0, []string{"mykey"}, []string{"myvalue"}), true), + []string{"mykey"}, []string{"myvalue"}): buildCounterMetric( + testStatsDMetric( + "statsdTestMetric1", + 7000, + false, + "c", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), true), testDescription("statsdTestMetric2", "c", - []string{"mykey"}, []string{"myvalue"}): buildCounterMetric(testStatsDMetric("statsdTestMetric2", 50, false, "c", 0, []string{"mykey"}, []string{"myvalue"}), true), + []string{"mykey"}, []string{"myvalue"}): buildCounterMetric( + testStatsDMetric( + "statsdTestMetric2", + 50, + false, + "c", + 0, + []string{"mykey"}, + []string{"myvalue"}, + 0, + ), true), }, }, } @@ -1084,12 +1490,52 @@ func TestStatsDParser_GetMetricsWithMetricType(t *testing.T) { assert.NoError(t, p.Initialize(true, false, false, []TimerHistogramMapping{{StatsdType: "timer", ObserverType: "gauge"}, {StatsdType: "histogram", ObserverType: "gauge"}})) instrument := newInstruments(nil) instrument.gauges[testDescription("statsdTestMetric1", "g", - []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"})] = buildGaugeMetric(testStatsDMetric("testGauge1", 1, false, "g", 0, []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}), time.Unix(711, 0)) + []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"})] = buildGaugeMetric( + testStatsDMetric( + "testGauge1", + 1, + false, + "g", + 0, + []string{"mykey", "metric_type"}, + []string{"myvalue", "gauge"}, + 0, + ), time.Unix(711, 0)) instrument.gauges[testDescription("statsdTestMetric1", "g", - []string{"mykey2", "metric_type"}, []string{"myvalue2", "gauge"})] = buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 10102, false, "g", 0, []string{"mykey2", "metric_type"}, []string{"myvalue2", "gauge"}), time.Unix(711, 0)) + []string{"mykey2", "metric_type"}, []string{"myvalue2", "gauge"})] = buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 10102, + false, + "g", + 0, + []string{"mykey2", "metric_type"}, + []string{"myvalue2", "gauge"}, + 0, + ), time.Unix(711, 0)) instrument.counters[testDescription("statsdTestMetric1", "g", - []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"})] = buildCounterMetric(testStatsDMetric("statsdTestMetric1", 10102, false, "g", 0, []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"}), false) - instrument.timersAndDistributions = append(instrument.timersAndDistributions, buildGaugeMetric(testStatsDMetric("statsdTestMetric1", 10102, false, "ms", 0, []string{"mykey2", "metric_type"}, []string{"myvalue2", "gauge"}), time.Unix(711, 0))) + []string{"mykey", "metric_type"}, []string{"myvalue", "gauge"})] = buildCounterMetric( + testStatsDMetric( + "statsdTestMetric1", + 10102, + false, + "g", + 0, + []string{"mykey", "metric_type"}, + []string{"myvalue", "gauge"}, + 0, + ), false) + instrument.timersAndDistributions = append(instrument.timersAndDistributions, buildGaugeMetric( + testStatsDMetric( + "statsdTestMetric1", + 10102, + false, + "ms", + 0, + []string{"mykey2", "metric_type"}, + []string{"myvalue2", "gauge"}, + 0, + ), time.Unix(711, 0))) instrument.summaries = map[statsDMetricDescription]summaryMetric{ testDescription("statsdTestMetric1", "h", []string{"mykey"}, []string{"myvalue"}): {