forked from mirrors/statsd_exporter
Merge pull request #210 from claytono/tag-parsing-optimizations
Tag parsing optimizations
This commit is contained in:
commit
d7eb1edeed
2 changed files with 66 additions and 11 deletions
57
exporter.go
57
exporter.go
|
@ -588,22 +588,59 @@ func buildEvent(statType, metric string, value float64, relative bool, labels ma
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleDogStatsDTagToKeyValue(labels map[string]string, component, tag string) {
|
||||||
|
// Bail early if the tag is empty
|
||||||
|
if len(tag) == 0 {
|
||||||
|
tagErrors.Inc()
|
||||||
|
log.Debugf("Malformed or empty DogStatsD tag %s in component %s", tag, component)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Skip hash if found.
|
||||||
|
if tag[0] == '#' {
|
||||||
|
tag = tag[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the first comma and split the tag into key and value.
|
||||||
|
var k, v string
|
||||||
|
for i, c := range tag {
|
||||||
|
if c == ':' {
|
||||||
|
k = tag[0:i]
|
||||||
|
v = tag[(i + 1):]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If either of them is empty, then either the k or v is empty, or we
|
||||||
|
// didn't find a colon, either way, throw an error and skip ahead.
|
||||||
|
if len(k) == 0 || len(v) == 0 {
|
||||||
|
tagErrors.Inc()
|
||||||
|
log.Debugf("Malformed or empty DogStatsD tag %s in component %s", tag, component)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
labels[escapeMetricName(k)] = v
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func parseDogStatsDTagsToLabels(component string) map[string]string {
|
func parseDogStatsDTagsToLabels(component string) map[string]string {
|
||||||
labels := map[string]string{}
|
labels := map[string]string{}
|
||||||
tagsReceived.Inc()
|
tagsReceived.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 {
|
lastTagEndIndex := 0
|
||||||
tagErrors.Inc()
|
for i, c := range component {
|
||||||
log.Debugf("Malformed or empty DogStatsD tag %s in component %s", t, component)
|
if c == ',' {
|
||||||
continue
|
tag := component[lastTagEndIndex:i]
|
||||||
|
lastTagEndIndex = i + 1
|
||||||
|
handleDogStatsDTagToKeyValue(labels, component, tag)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
labels[escapeMetricName(kv[0])] = kv[1]
|
// If we're not off the end of the string, add the last tag
|
||||||
|
if lastTagEndIndex < len(component) {
|
||||||
|
tag := component[lastTagEndIndex:]
|
||||||
|
handleDogStatsDTagToKeyValue(labels, component, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
return labels
|
return labels
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -685,7 +722,7 @@ samples:
|
||||||
multiplyEvents = int(1 / samplingFactor)
|
multiplyEvents = int(1 / samplingFactor)
|
||||||
}
|
}
|
||||||
case '#':
|
case '#':
|
||||||
labels = parseDogStatsDTagsToLabels(component)
|
labels = parseDogStatsDTagsToLabels(component[1:])
|
||||||
default:
|
default:
|
||||||
log.Debugf("Invalid sampling factor or tag section %s on line %s", components[2], line)
|
log.Debugf("Invalid sampling factor or tag section %s on line %s", components[2], line)
|
||||||
sampleErrors.WithLabelValues("invalid_sample_factor").Inc()
|
sampleErrors.WithLabelValues("invalid_sample_factor").Inc()
|
||||||
|
|
|
@ -572,3 +572,21 @@ func BenchmarkEscapeMetricName(b *testing.B) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkParseDogStatsDTagsToLabels(b *testing.B) {
|
||||||
|
scenarios := map[string]string{
|
||||||
|
"1 tag w/hash": "#test:tag",
|
||||||
|
"1 tag w/o hash": "test:tag",
|
||||||
|
"2 tags, mixed hashes": "tag1:test,#tag2:test",
|
||||||
|
"3 long tags": "tag1:reallylongtagthisisreallylong,tag2:anotherreallylongtag,tag3:thisisyetanotherextraordinarilylongtag",
|
||||||
|
"a-z tags": "a:0,b:1,c:2,d:3,e:4,f:5,g:6,h:7,i:8,j:9,k:0,l:1,m:2,n:3,o:4,p:5,q:6,r:7,s:8,t:9,u:0,v:1,w:2,x:3,y:4,z:5",
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tags := range scenarios {
|
||||||
|
b.Run(name, func(b *testing.B) {
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
parseDogStatsDTagsToLabels(tags)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue