diff --git a/pkg/line/line.go b/pkg/line/line.go index 30ca5d7d..11899798 100644 --- a/pkg/line/line.go +++ b/pkg/line/line.go @@ -226,6 +226,20 @@ func (p *Parser) LineToEvents(line string, sampleErrors prometheus.CounterVec, s return events } + // A DogStatsD line may carry a v1.2 container ID field (|c:) without any + // |# tags. The container ID field is always the final pipe-delimited field and + // its value may itself contain ':' (for example |c:sha256:...), so such a line + // must skip the legacy multi-metric ':' split below, which would otherwise + // shred the field and drop the sample as malformed_container_id. A valid legacy + // line always ends in a bare stat type (c, g, ms, ...), never "c:", so this + // check does not affect legacy multi-metric parsing. + usingDogStatsDContainerID := false + if idx := strings.LastIndex(elements[1], "|"); idx >= 0 { + if last := elements[1][idx+1:]; strings.HasPrefix(last, "c:") && len(last) > len("c:") { + usingDogStatsDContainerID = true + } + } + var samples []string lineParts := strings.SplitN(elements[1], "|", 3) if len(lineParts) < 2 { @@ -258,8 +272,8 @@ func (p *Parser) LineToEvents(line string, sampleErrors prometheus.CounterVec, s logger.Debug("bad line: invalid extended aggregate type", "line", line) return events } - } else if usingDogStatsDTags { - // disable multi-metrics + } else if usingDogStatsDTags || usingDogStatsDContainerID { + // disable multi-metrics for DogStatsD lines (|# tags and/or |c: container ID) samples = elements[1:] } else { samples = strings.Split(elements[1], ":") diff --git a/pkg/line/line_test.go b/pkg/line/line_test.go index 6f52764f..5baf6317 100644 --- a/pkg/line/line_test.go +++ b/pkg/line/line_test.go @@ -839,6 +839,46 @@ func TestLineToEvents(t *testing.T) { }, }, }, + "dogstatsd container ID without tags (counter)": { + in: "foo:100|c|c:container123", + out: event.Events{ + &event.CounterEvent{ + CMetricName: "foo", + CValue: 100, + CLabels: map[string]string{"container_id": "container123"}, + }, + }, + }, + "dogstatsd container ID without tags (gauge)": { + in: "foo:50|g|c:gauge_container", + out: event.Events{ + &event.GaugeEvent{ + GMetricName: "foo", + GValue: 50, + GLabels: map[string]string{"container_id": "gauge_container"}, + }, + }, + }, + "dogstatsd container ID without tags (timer)": { + in: "foo:1000|ms|c:timer_container", + out: event.Events{ + &event.ObserverEvent{ + OMetricName: "foo", + OValue: 1, + OLabels: map[string]string{"container_id": "timer_container"}, + }, + }, + }, + "dogstatsd container ID without tags (complex value)": { + in: "foo:100|c|c:sha256:abcd1234efgh5678", + out: event.Events{ + &event.CounterEvent{ + CMetricName: "foo", + CValue: 100, + CLabels: map[string]string{"container_id": "sha256:abcd1234efgh5678"}, + }, + }, + }, "dogstatsd container ID with tags": { in: "foo:100|c|#tag1:bar,tag2:baz|c:container456", out: event.Events{