Skip to content

Commit

Permalink
Support latest DogStatsD version (open-telemetry#31296)
Browse files Browse the repository at this point in the history
**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:** open-telemetry#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
```
  • Loading branch information
jverce authored and XinRanZhAWS committed Mar 13, 2024
1 parent d813814 commit 059ad50
Show file tree
Hide file tree
Showing 5 changed files with 575 additions and 70 deletions.
27 changes: 27 additions & 0 deletions .chloggen/feat_support-latest-dogstatsd.yaml
Original file line number Diff line number Diff line change
@@ -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]
1 change: 1 addition & 0 deletions receiver/statsdreceiver/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
24 changes: 24 additions & 0 deletions receiver/statsdreceiver/internal/protocol/statsd_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -128,6 +129,7 @@ type statsDMetric struct {
addition bool
unit string
sampleRate float64
timestamp uint64
}

type statsDMetricDescription struct {
Expand Down Expand Up @@ -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)
}
Expand Down
Loading

0 comments on commit 059ad50

Please sign in to comment.