Skip to content

Commit

Permalink
feat(inputs.statsd): Allow counters to report as float (#15371)
Browse files Browse the repository at this point in the history
  • Loading branch information
powersj authored May 17, 2024
1 parent 5239c97 commit 1e6eed5
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 0 deletions.
5 changes: 5 additions & 0 deletions plugins/inputs/statsd/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
## Replace dots (.) with underscore (_) and dashes (-) with
## double underscore (__) in metric names.
# convert_names = false

## Convert all numeric counters to float
## Enabling this would ensure that both counters and guages are both emitted
## as floats.
# float_counters = false
```

## Description
Expand Down
5 changes: 5 additions & 0 deletions plugins/inputs/statsd/sample.conf
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,8 @@
## Replace dots (.) with underscore (_) and dashes (-) with
## double underscore (__) in metric names.
# convert_names = false

## Convert all numeric counters to float
## Enabling this would ensure that both counters and guages are both emitted
## as floats.
# float_counters = false
6 changes: 6 additions & 0 deletions plugins/inputs/statsd/statsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ type Statsd struct {
DeleteSets bool `toml:"delete_sets"`
DeleteTimings bool `toml:"delete_timings"`
ConvertNames bool `toml:"convert_names"`
FloatCounters bool `toml:"float_counters"`

EnableAggregationTemporality bool `toml:"enable_aggregation_temporality"`

Expand Down Expand Up @@ -285,6 +286,11 @@ func (s *Statsd) Gather(acc telegraf.Accumulator) error {
m.fields["start_time"] = s.lastGatherTime.Format(time.RFC3339)
}

if s.FloatCounters {
for key := range m.fields {
m.fields[key] = float64(m.fields[key].(int64))
}
}
acc.AddCounter(m.name, m.fields, m.tags, now)
}
if s.DeleteCounters {
Expand Down
109 changes: 109 additions & 0 deletions plugins/inputs/statsd/statsd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,115 @@ func TestParse_Counters(t *testing.T) {
}
}

func TestParse_CountersAsFloat(t *testing.T) {
s := NewTestStatsd()
s.FloatCounters = true

// Test that counters work
validLines := []string{
"small.inc:1|c",
"big.inc:100|c",
"big.inc:1|c",
"big.inc:100000|c",
"big.inc:1000000|c",
"small.inc:1|c",
"zero.init:0|c",
"sample.rate:1|c|@0.1",
"sample.rate:1|c",
"scientific.notation:4.696E+5|c",
"negative.test:100|c",
"negative.test:-5|c",
}

for _, line := range validLines {
require.NoErrorf(t, s.parseStatsdLine(line), "Parsing line %s should not have resulted in an error", line)
}

validations := []struct {
name string
value int64
}{
{
"scientific_notation",
469600,
},
{
"small_inc",
2,
},
{
"big_inc",
1100101,
},
{
"zero_init",
0,
},
{
"sample_rate",
11,
},
{
"negative_test",
95,
},
}
for _, test := range validations {
require.NoError(t, testValidateCounter(test.name, test.value, s.counters))
}

expected := []telegraf.Metric{
testutil.MustMetric(
"small_inc",
map[string]string{"metric_type": "counter"},
map[string]interface{}{"value": 2.0},
time.Now(),
telegraf.Counter,
),
testutil.MustMetric(
"big_inc",
map[string]string{"metric_type": "counter"},
map[string]interface{}{"value": 1100101.0},
time.Now(),
telegraf.Counter,
),
testutil.MustMetric(
"zero_init",
map[string]string{"metric_type": "counter"},
map[string]interface{}{"value": 0.0},
time.Now(),
telegraf.Counter,
),
testutil.MustMetric(
"sample_rate",
map[string]string{"metric_type": "counter"},
map[string]interface{}{"value": 11.0},
time.Now(),
telegraf.Counter,
),
testutil.MustMetric(
"scientific_notation",
map[string]string{"metric_type": "counter"},
map[string]interface{}{"value": 469600.0},
time.Now(),
telegraf.Counter,
),
testutil.MustMetric(
"negative_test",
map[string]string{"metric_type": "counter"},
map[string]interface{}{"value": 95.0},
time.Now(),
telegraf.Counter,
),
}

acc := &testutil.Accumulator{}
require.NoError(t, s.Gather(acc))
metrics := acc.GetTelegrafMetrics()
testutil.PrintMetrics(metrics)
testutil.RequireMetricsEqual(t, expected, metrics, testutil.IgnoreTime(), testutil.SortMetrics())
}

// Tests low-level functionality of timings
func TestParse_Timings(t *testing.T) {
s := NewTestStatsd()
Expand Down

0 comments on commit 1e6eed5

Please sign in to comment.