Skip to content

Commit 15e57e1

Browse files
committed
Deprecate statsd convert_names option, expose separator
closes #876
1 parent 2f21535 commit 15e57e1

File tree

2 files changed

+62
-49
lines changed

2 files changed

+62
-49
lines changed

plugins/inputs/statsd/statsd.go

+16-20
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ const (
2121
UDP_PACKET_SIZE int = 1500
2222

2323
defaultFieldName = "value"
24+
25+
defaultSeparator = "_"
2426
)
2527

2628
var dropwarn = "ERROR: Message queue full. Discarding line [%s] " +
@@ -47,6 +49,8 @@ type Statsd struct {
4749
DeleteTimings bool
4850
ConvertNames bool
4951

52+
// MetricSeparator is the separator between parts of the metric name.
53+
MetricSeparator string
5054
// This flag enables parsing of tags in the dogstatsd extention to the
5155
// statsd protocol (http://docs.datadoghq.com/guides/dogstatsd/)
5256
ParseDataDogTags bool
@@ -76,23 +80,6 @@ type Statsd struct {
7680
listener *net.UDPConn
7781
}
7882

79-
func NewStatsd() *Statsd {
80-
s := Statsd{}
81-
82-
// Make data structures
83-
s.done = make(chan struct{})
84-
s.in = make(chan []byte, s.AllowedPendingMessages)
85-
s.gauges = make(map[string]cachedgauge)
86-
s.counters = make(map[string]cachedcounter)
87-
s.sets = make(map[string]cachedset)
88-
s.timings = make(map[string]cachedtimings)
89-
90-
s.ConvertNames = true
91-
s.UDPPacketSize = UDP_PACKET_SIZE
92-
93-
return &s
94-
}
95-
9683
// One statsd metric, form is <bucket>:<value>|<mtype>|@<samplerate>
9784
type metric struct {
9885
name string
@@ -149,8 +136,8 @@ const sampleConfig = `
149136
## Percentiles to calculate for timing & histogram stats
150137
percentiles = [90]
151138
152-
## convert measurement names, "." to "_" and "-" to "__"
153-
convert_names = true
139+
## separator to use between elements of a statsd metric
140+
metric_separator = "_"
154141
155142
## Parses tags in the datadog statsd format
156143
## http://docs.datadoghq.com/guides/dogstatsd/
@@ -257,6 +244,15 @@ func (s *Statsd) Start(_ telegraf.Accumulator) error {
257244
s.timings = prevInstance.timings
258245
}
259246

247+
if s.ConvertNames {
248+
log.Printf("WARNING statsd: convert_names config option is deprecated," +
249+
" please use metric_separator instead")
250+
}
251+
252+
if s.MetricSeparator == "" {
253+
s.MetricSeparator = defaultSeparator
254+
}
255+
260256
s.wg.Add(2)
261257
// Start the UDP listener
262258
go s.udpListen()
@@ -500,7 +496,7 @@ func (s *Statsd) parseName(bucket string) (string, string, map[string]string) {
500496

501497
var field string
502498
name := bucketparts[0]
503-
p, err := graphite.NewGraphiteParser(".", s.Templates, nil)
499+
p, err := graphite.NewGraphiteParser(s.MetricSeparator, s.Templates, nil)
504500
if err == nil {
505501
p.DefaultTags = tags
506502
name, tags, field, _ = p.ApplyTemplate(name)

plugins/inputs/statsd/statsd_test.go

+46-29
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,26 @@ import (
88
"github.com/influxdata/telegraf/testutil"
99
)
1010

11+
func NewTestStatsd() *Statsd {
12+
s := Statsd{}
13+
14+
// Make data structures
15+
s.done = make(chan struct{})
16+
s.in = make(chan []byte, s.AllowedPendingMessages)
17+
s.gauges = make(map[string]cachedgauge)
18+
s.counters = make(map[string]cachedcounter)
19+
s.sets = make(map[string]cachedset)
20+
s.timings = make(map[string]cachedtimings)
21+
22+
s.MetricSeparator = "_"
23+
s.UDPPacketSize = UDP_PACKET_SIZE
24+
25+
return &s
26+
}
27+
1128
// Invalid lines should return an error
1229
func TestParse_InvalidLines(t *testing.T) {
13-
s := NewStatsd()
30+
s := NewTestStatsd()
1431
invalid_lines := []string{
1532
"i.dont.have.a.pipe:45g",
1633
"i.dont.have.a.colon45|c",
@@ -34,7 +51,7 @@ func TestParse_InvalidLines(t *testing.T) {
3451

3552
// Invalid sample rates should be ignored and not applied
3653
func TestParse_InvalidSampleRate(t *testing.T) {
37-
s := NewStatsd()
54+
s := NewTestStatsd()
3855
invalid_lines := []string{
3956
"invalid.sample.rate:45|c|0.1",
4057
"invalid.sample.rate.2:45|c|@foo",
@@ -84,9 +101,9 @@ func TestParse_InvalidSampleRate(t *testing.T) {
84101
}
85102
}
86103

87-
// Names should be parsed like . -> _ and - -> __
104+
// Names should be parsed like . -> _
88105
func TestParse_DefaultNameParsing(t *testing.T) {
89-
s := NewStatsd()
106+
s := NewTestStatsd()
90107
valid_lines := []string{
91108
"valid:1|c",
92109
"valid.foo-bar:11|c",
@@ -108,7 +125,7 @@ func TestParse_DefaultNameParsing(t *testing.T) {
108125
1,
109126
},
110127
{
111-
"valid_foo__bar",
128+
"valid_foo-bar",
112129
11,
113130
},
114131
}
@@ -123,7 +140,7 @@ func TestParse_DefaultNameParsing(t *testing.T) {
123140

124141
// Test that template name transformation works
125142
func TestParse_Template(t *testing.T) {
126-
s := NewStatsd()
143+
s := NewTestStatsd()
127144
s.Templates = []string{
128145
"measurement.measurement.host.service",
129146
}
@@ -165,7 +182,7 @@ func TestParse_Template(t *testing.T) {
165182

166183
// Test that template filters properly
167184
func TestParse_TemplateFilter(t *testing.T) {
168-
s := NewStatsd()
185+
s := NewTestStatsd()
169186
s.Templates = []string{
170187
"cpu.idle.* measurement.measurement.host",
171188
}
@@ -207,7 +224,7 @@ func TestParse_TemplateFilter(t *testing.T) {
207224

208225
// Test that most specific template is chosen
209226
func TestParse_TemplateSpecificity(t *testing.T) {
210-
s := NewStatsd()
227+
s := NewTestStatsd()
211228
s.Templates = []string{
212229
"cpu.* measurement.foo.host",
213230
"cpu.idle.* measurement.measurement.host",
@@ -245,7 +262,7 @@ func TestParse_TemplateSpecificity(t *testing.T) {
245262

246263
// Test that most specific template is chosen
247264
func TestParse_TemplateFields(t *testing.T) {
248-
s := NewStatsd()
265+
s := NewTestStatsd()
249266
s.Templates = []string{
250267
"* measurement.measurement.field",
251268
}
@@ -359,7 +376,7 @@ func TestParse_Fields(t *testing.T) {
359376

360377
// Test that tags within the bucket are parsed correctly
361378
func TestParse_Tags(t *testing.T) {
362-
s := NewStatsd()
379+
s := NewTestStatsd()
363380

364381
tests := []struct {
365382
bucket string
@@ -412,7 +429,7 @@ func TestParse_Tags(t *testing.T) {
412429

413430
// Test that DataDog tags are parsed
414431
func TestParse_DataDogTags(t *testing.T) {
415-
s := NewStatsd()
432+
s := NewTestStatsd()
416433
s.ParseDataDogTags = true
417434

418435
lines := []string{
@@ -490,7 +507,7 @@ func tagsForItem(m interface{}) map[string]string {
490507

491508
// Test that statsd buckets are parsed to measurement names properly
492509
func TestParseName(t *testing.T) {
493-
s := NewStatsd()
510+
s := NewTestStatsd()
494511

495512
tests := []struct {
496513
in_name string
@@ -506,7 +523,7 @@ func TestParseName(t *testing.T) {
506523
},
507524
{
508525
"foo.bar-baz",
509-
"foo_bar__baz",
526+
"foo_bar-baz",
510527
},
511528
}
512529

@@ -517,8 +534,8 @@ func TestParseName(t *testing.T) {
517534
}
518535
}
519536

520-
// Test with ConvertNames = false
521-
s.ConvertNames = false
537+
// Test with separator == "."
538+
s.MetricSeparator = "."
522539

523540
tests = []struct {
524541
in_name string
@@ -549,7 +566,7 @@ func TestParseName(t *testing.T) {
549566
// Test that measurements with the same name, but different tags, are treated
550567
// as different outputs
551568
func TestParse_MeasurementsWithSameName(t *testing.T) {
552-
s := NewStatsd()
569+
s := NewTestStatsd()
553570

554571
// Test that counters work
555572
valid_lines := []string{
@@ -607,8 +624,8 @@ func TestParse_MeasurementsWithMultipleValues(t *testing.T) {
607624
"valid.multiple.mixed:1|c:1|ms:2|s:1|g",
608625
}
609626

610-
s_single := NewStatsd()
611-
s_multiple := NewStatsd()
627+
s_single := NewTestStatsd()
628+
s_multiple := NewTestStatsd()
612629

613630
for _, line := range single_lines {
614631
err := s_single.parseStatsdLine(line)
@@ -701,7 +718,7 @@ func TestParse_MeasurementsWithMultipleValues(t *testing.T) {
701718

702719
// Valid lines should be parsed and their values should be cached
703720
func TestParse_ValidLines(t *testing.T) {
704-
s := NewStatsd()
721+
s := NewTestStatsd()
705722
valid_lines := []string{
706723
"valid:45|c",
707724
"valid:45|s",
@@ -720,7 +737,7 @@ func TestParse_ValidLines(t *testing.T) {
720737

721738
// Tests low-level functionality of gauges
722739
func TestParse_Gauges(t *testing.T) {
723-
s := NewStatsd()
740+
s := NewTestStatsd()
724741

725742
// Test that gauge +- values work
726743
valid_lines := []string{
@@ -786,7 +803,7 @@ func TestParse_Gauges(t *testing.T) {
786803

787804
// Tests low-level functionality of sets
788805
func TestParse_Sets(t *testing.T) {
789-
s := NewStatsd()
806+
s := NewTestStatsd()
790807

791808
// Test that sets work
792809
valid_lines := []string{
@@ -834,7 +851,7 @@ func TestParse_Sets(t *testing.T) {
834851

835852
// Tests low-level functionality of counters
836853
func TestParse_Counters(t *testing.T) {
837-
s := NewStatsd()
854+
s := NewTestStatsd()
838855

839856
// Test that counters work
840857
valid_lines := []string{
@@ -888,7 +905,7 @@ func TestParse_Counters(t *testing.T) {
888905

889906
// Tests low-level functionality of timings
890907
func TestParse_Timings(t *testing.T) {
891-
s := NewStatsd()
908+
s := NewTestStatsd()
892909
s.Percentiles = []int{90}
893910
acc := &testutil.Accumulator{}
894911

@@ -925,7 +942,7 @@ func TestParse_Timings(t *testing.T) {
925942
// Tests low-level functionality of timings when multiple fields is enabled
926943
// and a measurement template has been defined which can parse field names
927944
func TestParse_Timings_MultipleFieldsWithTemplate(t *testing.T) {
928-
s := NewStatsd()
945+
s := NewTestStatsd()
929946
s.Templates = []string{"measurement.field"}
930947
s.Percentiles = []int{90}
931948
acc := &testutil.Accumulator{}
@@ -974,7 +991,7 @@ func TestParse_Timings_MultipleFieldsWithTemplate(t *testing.T) {
974991
// but a measurement template hasn't been defined so we can't parse field names
975992
// In this case the behaviour should be the same as normal behaviour
976993
func TestParse_Timings_MultipleFieldsWithoutTemplate(t *testing.T) {
977-
s := NewStatsd()
994+
s := NewTestStatsd()
978995
s.Templates = []string{}
979996
s.Percentiles = []int{90}
980997
acc := &testutil.Accumulator{}
@@ -1022,7 +1039,7 @@ func TestParse_Timings_MultipleFieldsWithoutTemplate(t *testing.T) {
10221039
}
10231040

10241041
func TestParse_Timings_Delete(t *testing.T) {
1025-
s := NewStatsd()
1042+
s := NewTestStatsd()
10261043
s.DeleteTimings = true
10271044
fakeacc := &testutil.Accumulator{}
10281045
var err error
@@ -1046,7 +1063,7 @@ func TestParse_Timings_Delete(t *testing.T) {
10461063

10471064
// Tests the delete_gauges option
10481065
func TestParse_Gauges_Delete(t *testing.T) {
1049-
s := NewStatsd()
1066+
s := NewTestStatsd()
10501067
s.DeleteGauges = true
10511068
fakeacc := &testutil.Accumulator{}
10521069
var err error
@@ -1072,7 +1089,7 @@ func TestParse_Gauges_Delete(t *testing.T) {
10721089

10731090
// Tests the delete_sets option
10741091
func TestParse_Sets_Delete(t *testing.T) {
1075-
s := NewStatsd()
1092+
s := NewTestStatsd()
10761093
s.DeleteSets = true
10771094
fakeacc := &testutil.Accumulator{}
10781095
var err error
@@ -1098,7 +1115,7 @@ func TestParse_Sets_Delete(t *testing.T) {
10981115

10991116
// Tests the delete_counters option
11001117
func TestParse_Counters_Delete(t *testing.T) {
1101-
s := NewStatsd()
1118+
s := NewTestStatsd()
11021119
s.DeleteCounters = true
11031120
fakeacc := &testutil.Accumulator{}
11041121
var err error

0 commit comments

Comments
 (0)