Skip to content

Commit

Permalink
Fix panic with empty datadog tag string (influxdata#6088)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielnelson authored and Mathieu Lecarme committed Apr 17, 2020
1 parent 3f9cb40 commit 6c61442
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 69 deletions.
4 changes: 4 additions & 0 deletions plugins/inputs/statsd/datadog.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ func (s *Statsd) parseEventMessage(now time.Time, message string, defaultHostnam
}

func parseDataDogTags(tags map[string]string, message string) {
if len(message) == 0 {
return
}

start, i := 0, 0
var k string
var inVal bool // check if we are parsing the value part of the tag
Expand Down
175 changes: 106 additions & 69 deletions plugins/inputs/statsd/statsd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -847,85 +847,122 @@ func TestParse_Tags(t *testing.T) {
}
}

// Test that DataDog tags are parsed
func TestParse_DataDogTags(t *testing.T) {
s := NewTestStatsd()
s.DataDogExtensions = true

lines := []string{
"my_counter:1|c|#host:localhost,environment:prod,endpoint:/:tenant?/oauth/ro",
"my_gauge:10.1|g|#live",
"my_set:1|s|#host:localhost",
"my_timer:3|ms|@0.1|#live,host:localhost",
}

expectedTags := map[string]map[string]string{
"my_counter": {
"host": "localhost",
"environment": "prod",
"endpoint": "/:tenant?/oauth/ro",
"metric_type": "counter",
tests := []struct {
name string
line string
expected []telegraf.Metric
}{
{
name: "counter",
line: "my_counter:1|c|#host:localhost,environment:prod,endpoint:/:tenant?/oauth/ro",
expected: []telegraf.Metric{
testutil.MustMetric(
"my_counter",
map[string]string{
"endpoint": "/:tenant?/oauth/ro",
"environment": "prod",
"host": "localhost",
"metric_type": "counter",
},
map[string]interface{}{
"value": 1,
},
time.Now(),
),
},
},

"my_gauge": {
"live": "true",
"metric_type": "gauge",
{
name: "gauge",
line: "my_gauge:10.1|g|#live",
expected: []telegraf.Metric{
testutil.MustMetric(
"my_gauge",
map[string]string{
"live": "true",
"metric_type": "gauge",
},
map[string]interface{}{
"value": 10.1,
},
time.Now(),
),
},
},

"my_set": {
"host": "localhost",
"metric_type": "set",
{
name: "set",
line: "my_set:1|s|#host:localhost",
expected: []telegraf.Metric{
testutil.MustMetric(
"my_set",
map[string]string{
"host": "localhost",
"metric_type": "set",
},
map[string]interface{}{
"value": 1,
},
time.Now(),
),
},
},

"my_timer": {
"live": "true",
"host": "localhost",
"metric_type": "timing",
{
name: "timer",
line: "my_timer:3|ms|@0.1|#live,host:localhost",
expected: []telegraf.Metric{
testutil.MustMetric(
"my_timer",
map[string]string{
"host": "localhost",
"live": "true",
"metric_type": "timing",
},
map[string]interface{}{
"count": 10,
"lower": float64(3),
"mean": float64(3),
"stddev": float64(0),
"sum": float64(30),
"upper": float64(3),
},
time.Now(),
),
},
},
{
name: "empty tag set",
line: "cpu:42|c|#",
expected: []telegraf.Metric{
testutil.MustMetric(
"cpu",
map[string]string{
"metric_type": "counter",
},
map[string]interface{}{
"value": 42,
},
time.Now(),
),
},
},
}

for _, line := range lines {
err := s.parseStatsdLine(line)
if err != nil {
t.Errorf("Parsing line %s should not have resulted in an error\n", line)
}
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var acc testutil.Accumulator

actualTags := map[string]map[string]string{
"my_gauge": tagsForItem(s.gauges),
"my_counter": tagsForItem(s.counters),
"my_set": tagsForItem(s.sets),
"my_timer": tagsForItem(s.timings),
}
for name, tags := range expectedTags {
for expectedK, expectedV := range tags {
if expectedV != actualTags[name][expectedK] {
t.Errorf("failed: expected: %#v != %#v", tags, actualTags[name])
}
}
}
}
s := NewTestStatsd()
s.DataDogExtensions = true

func tagsForItem(m interface{}) map[string]string {
switch m.(type) {
case map[string]cachedcounter:
for _, v := range m.(map[string]cachedcounter) {
return v.tags
}
case map[string]cachedgauge:
for _, v := range m.(map[string]cachedgauge) {
return v.tags
}
case map[string]cachedset:
for _, v := range m.(map[string]cachedset) {
return v.tags
}
case map[string]cachedtimings:
for _, v := range m.(map[string]cachedtimings) {
return v.tags
}
err := s.parseStatsdLine(tt.line)
require.NoError(t, err)
err = s.Gather(&acc)
require.NoError(t, err)

testutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(),
testutil.SortMetrics(), testutil.IgnoreTime())
})
}
return nil
}

// Test that statsd buckets are parsed to measurement names properly
Expand Down

0 comments on commit 6c61442

Please sign in to comment.