forked from mirrors/statsd_exporter
DogStatsD: review changes
This commit is contained in:
parent
8f36baf045
commit
0b792e0be6
3 changed files with 80 additions and 30 deletions
10
README.md
10
README.md
|
@ -26,6 +26,16 @@ We recommend this only as an intermediate solution and recommend switching to
|
|||
[native Prometheus instrumentation](http://prometheus.io/docs/instrumenting/clientlibs/)
|
||||
in the long term.
|
||||
|
||||
### DogStatsD extensions
|
||||
|
||||
The exporter will convert DogStatsD-style tags to prometheus labels. See
|
||||
[Tags](http://docs.datadoghq.com/guides/dogstatsd/#tags) in the DogStatsD
|
||||
documentation for the concept description and
|
||||
[Datagram Format](http://docs.datadoghq.com/guides/dogstatsd/#datagram-format)
|
||||
for specifics. It boils down to appending
|
||||
`|#tag:value,another_tag:another_value` to the normal StatsD format. Tags
|
||||
without values (`#some_tag`) are not supported.
|
||||
|
||||
## Building and Running
|
||||
|
||||
$ go build
|
||||
|
|
|
@ -58,42 +58,82 @@ func TestHandlePacket(t *testing.T) {
|
|||
},
|
||||
}, {
|
||||
name: "datadog tag extension",
|
||||
in: "foo:100|c|#tag1:bar,tag2:baz,tag3,tag4",
|
||||
in: "foo:100|c|#tag1:bar,tag2:baz",
|
||||
out: Events{
|
||||
&CounterEvent{
|
||||
metricName: "foo",
|
||||
value: 100,
|
||||
labels: map[string]string{"tag1": "bar", "tag2": "baz", "tag3": ".", "tag4": "."},
|
||||
labels: map[string]string{"tag1": "bar", "tag2": "baz"},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "datadog tag extension with # in all keys (as sent by datadog php client)",
|
||||
in: "foo:100|c|#tag1:bar,#tag2:baz,#tag3,#tag4",
|
||||
in: "foo:100|c|#tag1:bar,#tag2:baz",
|
||||
out: Events{
|
||||
&CounterEvent{
|
||||
metricName: "foo",
|
||||
value: 100,
|
||||
labels: map[string]string{"tag1": "bar", "tag2": "baz", "tag3": ".", "tag4": "."},
|
||||
labels: map[string]string{"tag1": "bar", "tag2": "baz"},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "datadog tag extension with tags unsupported by prometheus",
|
||||
in: "foo:100|c|#09digits:0,tag.with.dots,tag_with_empty_value:",
|
||||
name: "datadog tag extension with tag keys unsupported by prometheus",
|
||||
in: "foo:100|c|#09digits:0,tag.with.dots:1",
|
||||
out: Events{
|
||||
&CounterEvent{
|
||||
metricName: "foo",
|
||||
value: 100,
|
||||
labels: map[string]string{"_09digits": "0", "tag_with_dots": ".", "tag_with_empty_value": "."},
|
||||
labels: map[string]string{"_09digits": "0", "tag_with_dots": "1"},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "datadog tag extension with valueless tags: ignored",
|
||||
in: "foo:100|c|#tag_without_a_value",
|
||||
out: Events{
|
||||
&CounterEvent{
|
||||
metricName: "foo",
|
||||
value: 100,
|
||||
labels: map[string]string{},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "datadog tag extension with valueless tags (edge case)",
|
||||
in: "foo:100|c|#tag_without_a_value,tag:value",
|
||||
out: Events{
|
||||
&CounterEvent{
|
||||
metricName: "foo",
|
||||
value: 100,
|
||||
labels: map[string]string{"tag": "value"},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "datadog tag extension with empty tags (edge case)",
|
||||
in: "foo:100|c|#tag:value,,",
|
||||
out: Events{
|
||||
&CounterEvent{
|
||||
metricName: "foo",
|
||||
value: 100,
|
||||
labels: map[string]string{"tag": "value"},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "datadog tag extension with sampling",
|
||||
in: "foo:100|c|@0.1|#tag1:bar,tag2,tag3:baz",
|
||||
in: "foo:100|c|@0.1|#tag1:bar,#tag2:baz",
|
||||
out: Events{
|
||||
&CounterEvent{
|
||||
metricName: "foo",
|
||||
value: 1000,
|
||||
labels: map[string]string{"tag1": "bar", "tag2": ".", "tag3": "baz"},
|
||||
labels: map[string]string{"tag1": "bar", "tag2": "baz"},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "datadog tag extension with multiple colons",
|
||||
in: "foo:100|c|@0.1|#tag1:foo:bar",
|
||||
out: Events{
|
||||
&CounterEvent{
|
||||
metricName: "foo",
|
||||
value: 1000,
|
||||
labels: map[string]string{"tag1": "foo:bar"},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
|
|
42
exporter.go
42
exporter.go
|
@ -303,6 +303,25 @@ func (l *StatsDListener) Listen(e chan<- Events) {
|
|||
}
|
||||
}
|
||||
|
||||
func parseDogStatsDTagsToLabels(component string) map[string]string {
|
||||
labels := map[string]string{}
|
||||
networkStats.WithLabelValues("dogstatsd_tags").Inc()
|
||||
tags := strings.Split(component, ",")
|
||||
for _, t := range tags {
|
||||
t = strings.TrimPrefix(t, "#")
|
||||
kv := strings.SplitN(t, ":", 2)
|
||||
|
||||
if len(kv) < 2 || len(kv[1]) == 0 {
|
||||
networkStats.WithLabelValues("malformed_dogstatsd_tag").Inc()
|
||||
log.Printf("Malformed or empty DogStatsD tag %s in component %s", t, component)
|
||||
continue
|
||||
}
|
||||
|
||||
labels[escapeMetricName(kv[0])] = kv[1]
|
||||
}
|
||||
return labels
|
||||
}
|
||||
|
||||
func (l *StatsDListener) handlePacket(packet []byte, e chan<- Events) {
|
||||
lines := strings.Split(string(packet), "\n")
|
||||
events := Events{}
|
||||
|
@ -334,7 +353,6 @@ func (l *StatsDListener) handlePacket(packet []byte, e chan<- Events) {
|
|||
continue
|
||||
}
|
||||
valueStr, statType := components[0], components[1]
|
||||
labels := map[string]string{}
|
||||
value, err := strconv.ParseFloat(valueStr, 64)
|
||||
if err != nil {
|
||||
log.Printf("Bad value %s on line: %s", valueStr, line)
|
||||
|
@ -342,6 +360,7 @@ func (l *StatsDListener) handlePacket(packet []byte, e chan<- Events) {
|
|||
continue
|
||||
}
|
||||
|
||||
labels := map[string]string{}
|
||||
if len(components) >= 3 {
|
||||
for _, component := range components[2:] {
|
||||
switch component[0] {
|
||||
|
@ -360,26 +379,7 @@ func (l *StatsDListener) handlePacket(packet []byte, e chan<- Events) {
|
|||
}
|
||||
value /= samplingFactor
|
||||
case '#':
|
||||
networkStats.WithLabelValues("dogstatsd_tags").Inc()
|
||||
tags := strings.Split(component, ",")
|
||||
for _, t := range tags {
|
||||
t = strings.TrimPrefix(t, "#")
|
||||
kv := strings.Split(t, ":")
|
||||
tag_key := kv[0]
|
||||
tag_key = escapeMetricName(tag_key)
|
||||
|
||||
var tag_value string
|
||||
if len(kv) == 2 {
|
||||
if len(kv[1]) > 0 {
|
||||
tag_value = kv[1]
|
||||
} else {
|
||||
tag_value = "."
|
||||
}
|
||||
} else if len(kv) == 1 {
|
||||
tag_value = "."
|
||||
}
|
||||
labels[tag_key] = tag_value
|
||||
}
|
||||
labels = parseDogStatsDTagsToLabels(component)
|
||||
default:
|
||||
log.Printf("Invalid sampling factor or tag section %s on line %s", components[2], line)
|
||||
networkStats.WithLabelValues("invalid_sample_factor").Inc()
|
||||
|
|
Loading…
Reference in a new issue