Skip to content

Commit 19b86b3

Browse files
authored
Merge pull request #3 from dreamboxlearning/feature/add-per-metric-tag
Add per metric tags
2 parents 76992c9 + e340705 commit 19b86b3

File tree

5 files changed

+104
-25
lines changed

5 files changed

+104
-25
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@
1313

1414
# Dependency directories
1515
vendor/
16+
17+
#IntelliJ
18+
.idea/

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ require (
66
github.com/DataDog/datadog-go v4.6.0+incompatible
77
github.com/Microsoft/go-winio v0.5.0 // indirect
88
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475
9-
github.com/stretchr/testify v1.7.0 // indirect
9+
github.com/stretchr/testify v1.7.0
1010
)

go.sum

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
1919
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
2020
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
2121
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
22+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
2223
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
2324
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
2425
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

reporter.go

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package datadog
33
import (
44
"fmt"
55
"log"
6+
"regexp"
67
"runtime"
8+
"strings"
79
"time"
810

911
"github.com/DataDog/datadog-go/statsd"
@@ -14,6 +16,10 @@ const (
1416
defaultFlushInterval = time.Second * 10
1517
)
1618

19+
// Expect the tags in the pattern
20+
// namespace.metricName[tag1:value1,tag2:value2,etc....]
21+
var tagPattern = regexp.MustCompile("([\\w\\.]+)\\[([\\w\\W]+)\\]")
22+
1723
// Reporter wraps a metrics registry with a given statsd client.
1824
type Reporter struct {
1925
// Registry matrices that need to be reported to the Client
@@ -79,61 +85,63 @@ func (r *Reporter) Flush() {
7985
// be used in a loop similarly to FlushWithInterval for custom error handling or
8086
// data submission variations.
8187
func (r *Reporter) FlushOnce() error {
82-
r.Registry.Each(func(name string, i interface{}) {
88+
r.Registry.Each(func(metricName string, i interface{}) {
89+
name, tags := r.splitNameAndTags(metricName)
90+
8391
switch metric := i.(type) {
8492
case metrics.Counter:
8593
v := metric.Count()
8694
l := r.ss[name]
87-
r.Client.Count(name, v-l, r.tags, 1)
95+
r.Client.Count(name, v-l, tags, 1)
8896
r.ss[name] = v
8997

9098
case metrics.Gauge:
91-
r.Client.Gauge(name, float64(metric.Value()), r.tags, 1)
99+
r.Client.Gauge(name, float64(metric.Value()), tags, 1)
92100

93101
case metrics.GaugeFloat64:
94-
r.Client.Gauge(name, metric.Value(), r.tags, 1)
102+
r.Client.Gauge(name, metric.Value(), tags, 1)
95103

96104
case metrics.Histogram:
97105
ms := metric.Snapshot()
98106

99-
r.Client.Gauge(name+".count", float64(ms.Count()), r.tags, 1)
100-
r.Client.Gauge(name+".max", float64(ms.Max()), r.tags, 1)
101-
r.Client.Gauge(name+".min", float64(ms.Min()), r.tags, 1)
102-
r.Client.Gauge(name+".mean", ms.Mean(), r.tags, 1)
103-
r.Client.Gauge(name+".stddev", ms.StdDev(), r.tags, 1)
104-
r.Client.Gauge(name+".sum", float64(ms.Sum()), r.tags, 1)
105-
r.Client.Gauge(name+".var", ms.Variance(), r.tags, 1)
107+
r.Client.Gauge(name+".count", float64(ms.Count()), tags, 1)
108+
r.Client.Gauge(name+".max", float64(ms.Max()), tags, 1)
109+
r.Client.Gauge(name+".min", float64(ms.Min()), tags, 1)
110+
r.Client.Gauge(name+".mean", ms.Mean(), tags, 1)
111+
r.Client.Gauge(name+".stddev", ms.StdDev(), tags, 1)
112+
r.Client.Gauge(name+".sum", float64(ms.Sum()), tags, 1)
113+
r.Client.Gauge(name+".var", ms.Variance(), tags, 1)
106114

107115
if len(r.percentiles) > 0 {
108116
values := ms.Percentiles(r.percentiles)
109117
for i, p := range r.p {
110-
r.Client.Gauge(name+p, values[i], r.tags, 1)
118+
r.Client.Gauge(name+p, values[i], tags, 1)
111119
}
112120
}
113121

114122
case metrics.Meter:
115123
ms := metric.Snapshot()
116124

117-
r.Client.Gauge(name+".count", float64(ms.Count()), r.tags, 1)
118-
r.Client.Gauge(name+".rate1", ms.Rate1(), r.tags, 1)
119-
r.Client.Gauge(name+".rate5", ms.Rate5(), r.tags, 1)
120-
r.Client.Gauge(name+".rate15", ms.Rate15(), r.tags, 1)
121-
r.Client.Gauge(name+".mean", ms.RateMean(), r.tags, 1)
125+
r.Client.Gauge(name+".count", float64(ms.Count()), tags, 1)
126+
r.Client.Gauge(name+".rate1", ms.Rate1(), tags, 1)
127+
r.Client.Gauge(name+".rate5", ms.Rate5(), tags, 1)
128+
r.Client.Gauge(name+".rate15", ms.Rate15(), tags, 1)
129+
r.Client.Gauge(name+".mean", ms.RateMean(), tags, 1)
122130

123131
case metrics.Timer:
124132
ms := metric.Snapshot()
125133

126-
r.Client.Gauge(name+".count", float64(ms.Count()), r.tags, 1)
127-
r.Client.Gauge(name+".max", time.Duration(ms.Max()).Seconds()*1000, r.tags, 1)
128-
r.Client.Gauge(name+".min", time.Duration(ms.Min()).Seconds()*1000, r.tags, 1)
129-
r.Client.Gauge(name+".mean", time.Duration(ms.Mean()).Seconds()*1000, r.tags, 1)
130-
r.Client.Gauge(name+".stddev", time.Duration(ms.StdDev()).Seconds()*1000, r.tags, 1)
131-
r.Client.Gauge(name+".sum", float64(ms.Sum()), r.tags, 1)
134+
r.Client.Gauge(name+".count", float64(ms.Count()), tags, 1)
135+
r.Client.Gauge(name+".max", time.Duration(ms.Max()).Seconds()*1000, tags, 1)
136+
r.Client.Gauge(name+".min", time.Duration(ms.Min()).Seconds()*1000, tags, 1)
137+
r.Client.Gauge(name+".mean", time.Duration(ms.Mean()).Seconds()*1000, tags, 1)
138+
r.Client.Gauge(name+".stddev", time.Duration(ms.StdDev()).Seconds()*1000, tags, 1)
139+
r.Client.Gauge(name+".sum", float64(ms.Sum()), tags, 1)
132140

133141
if len(r.percentiles) > 0 {
134142
values := ms.Percentiles(r.percentiles)
135143
for i, p := range r.p {
136-
r.Client.Gauge(name+p, time.Duration(values[i]).Seconds()*1000, r.tags, 1)
144+
r.Client.Gauge(name+p, time.Duration(values[i]).Seconds()*1000, tags, 1)
137145
}
138146
}
139147
}
@@ -153,3 +161,14 @@ func handlePanic(rec interface{}) {
153161
}
154162
log.Printf("Recovered from panic: %#v \n%v", rec, callers)
155163
}
164+
165+
func (r *Reporter) splitNameAndTags(metric string) (string, []string) {
166+
if res := tagPattern.FindStringSubmatch(metric); len(res) == 3 {
167+
if r.tags == nil {
168+
return res[1], append(strings.Split(res[2], ","))
169+
} else {
170+
return res[1], append(strings.Split(res[2], ","), r.tags...)
171+
}
172+
}
173+
return metric, r.tags
174+
}

reporter_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package datadog
2+
3+
import (
4+
"github.com/rcrowley/go-metrics"
5+
"github.com/stretchr/testify/assert"
6+
"testing"
7+
)
8+
9+
func TestSplitNameAndTagsNoTags(t *testing.T) {
10+
reporter := &Reporter{
11+
Registry: metrics.DefaultRegistry,
12+
}
13+
14+
var metricName = "test.metric_name"
15+
name, tags := reporter.splitNameAndTags(metricName)
16+
assert.NotNil(t, name, "name")
17+
assert.Nil(t, tags, "tags")
18+
19+
assert.Equal(t, "test.metric_name", name)
20+
}
21+
22+
func TestSplitNameAndTagsSingleTag(t *testing.T) {
23+
reporter := &Reporter{
24+
Registry: metrics.DefaultRegistry,
25+
}
26+
27+
var metricName = "test.httpcall[method:GET]"
28+
29+
name, tags := reporter.splitNameAndTags(metricName)
30+
assert.NotNil(t, name, "name")
31+
assert.NotNil(t, tags, "tags")
32+
assert.Equal(t, 1, len(tags))
33+
34+
assert.Equal(t, "test.httpcall", name)
35+
assert.Equal(t, "method:GET", tags[0])
36+
}
37+
38+
func TestSplitNameAndTagsMultipleTag(t *testing.T) {
39+
globalTags := []string{"globaltag:true"}
40+
reporter := &Reporter{
41+
Registry: metrics.DefaultRegistry,
42+
tags: globalTags,
43+
}
44+
45+
var metricName = "test.httpcall[method:GET]"
46+
47+
name, tags := reporter.splitNameAndTags(metricName)
48+
assert.NotNil(t, name, "name")
49+
assert.NotNil(t, tags, "tags")
50+
//expect two tags: the global tag and the metric level tag
51+
assert.Equal(t, 2, len(tags))
52+
53+
assert.Equal(t, "test.httpcall", name)
54+
assert.Equal(t, "method:GET", tags[0])
55+
assert.Equal(t, "globaltag:true", tags[1])
56+
}

0 commit comments

Comments
 (0)