Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased]
- Put unreleased items here.

## [2.0.0] - 2020-05-28

- Go module support
- Go 1.12-1.14 support
- Upgrade to datadog-go 3.x
- Adds support for DataDog Distributions: https://docs.datadoghq.com/metrics/distributions/
- Adds Close() to Client interface to support intentional flushes when applications are shutting down
- Optimize tag handling

## [1.4.0] - 2019-08-26

- Updated `datadog-go` to version `2.2.0`
Expand Down
56 changes: 56 additions & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 42 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Gopkg.toml example
#
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true


[[constraint]]
name = "github.com/DataDog/datadog-go"
version = "3.7.1"

[[constraint]]
name = "github.com/mattn/go-isatty"
version = "0.0.12"

[[constraint]]
branch = "master"
name = "github.com/mgutz/ansi"

[prune]
go-tests = true
unused-packages = true
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ if os.Getenv("env") == "prod" {
// Log to standard out instead of sending production metrics.
client = metrics.NewLoggerClient(nil)
}
defer client.Close()

// Simple incrementing counter
client.Incr("requests.count")
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ module github.com/istreamlabs/go-metrics
go 1.12

require (
github.com/DataDog/datadog-go v3.4.1+incompatible
github.com/DataDog/datadog-go v3.7.1+incompatible
github.com/mattn/go-colorable v0.1.6 // indirect
github.com/mattn/go-isatty v0.0.12
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
github.com/stretchr/testify v1.5.1 // indirect
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect
gopkg.in/go-playground/assert.v1 v1.2.1
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
github.com/DataDog/datadog-go v3.4.1+incompatible h1:hRUopimy+td4Lc3QDvP/hsbQKI3n5xsmGJTRghwaA7U=
github.com/DataDog/datadog-go v3.4.1+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/datadog-go v3.7.1+incompatible h1:HmA9qHVrHIAqpSvoCYJ+c6qst0lgqEhNW6/KwfkHbS8=
github.com/DataDog/datadog-go v3.7.1+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
Expand All @@ -20,5 +22,7 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
24 changes: 10 additions & 14 deletions metrics/datadog.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
type DataDogClient struct {
client *statsd.Client
rate float64
tagMap map[string]string
tags []string
}

// NewDataDogClient creates a new dogstatsd client pointing to `address` with
Expand Down Expand Up @@ -39,7 +39,7 @@ func (c *DataDogClient) WithRate(rate float64) Client {
return &DataDogClient{
client: c.client,
rate: rate,
tagMap: combine(c.tagMap, map[string]string{}),
tags: c.tags, // clone isn't necessary since original slice is immutable
}
}

Expand All @@ -49,22 +49,18 @@ func (c *DataDogClient) WithTags(tags map[string]string) Client {
return &DataDogClient{
client: c.client,
rate: c.rate,
tagMap: combine(c.tagMap, tags),
tags: cloneTagsWithMap(c.tags, tags),
}
}

func (c *DataDogClient) tagsList() []string {
return mapToStrings(c.tagMap)
}

// Close closes all client connections and flushes any buffered data.
func (c *DataDogClient) Close() error {
return c.client.Close()
}

// Count adds some integer value to a metric.
func (c *DataDogClient) Count(name string, value int64) {
c.client.Count(name, value, c.tagsList(), c.rate)
c.client.Count(name, value, c.tags, c.rate)
}

// Incr adds one to a metric.
Expand All @@ -79,29 +75,29 @@ func (c *DataDogClient) Decr(name string) {

// Gauge sets a numeric value.
func (c *DataDogClient) Gauge(name string, value float64) {
c.client.Gauge(name, value, c.tagsList(), c.rate)
c.client.Gauge(name, value, c.tags, c.rate)
}

// Event tracks an event that may be relevant to other metrics.
func (c *DataDogClient) Event(e *statsd.Event) {
if len(c.tagMap) > 0 {
e.Tags = append(e.Tags, c.tagsList()...)
if len(c.tags) > 0 {
e.Tags = append(e.Tags, c.tags...)
}

c.client.Event(e)
}

// Timing tracks a duration.
func (c *DataDogClient) Timing(name string, value time.Duration) {
c.client.Timing(name, value, c.tagsList(), c.rate)
c.client.Timing(name, value, c.tags, c.rate)
}

// Histogram sets a numeric value while tracking min/max/avg/p95/etc.
func (c *DataDogClient) Histogram(name string, value float64) {
c.client.Histogram(name, value, c.tagsList(), c.rate)
c.client.Histogram(name, value, c.tags, c.rate)
}

// Distribution tracks the statistical distribution of a set of values.
func (c *DataDogClient) Distribution(name string, value float64) {
c.client.Distribution(name, value, c.tagsList(), c.rate)
c.client.Distribution(name, value, c.tags, c.rate)
}
66 changes: 61 additions & 5 deletions metrics/datadog_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package metrics_test

import (
"fmt"
"reflect"
"testing"
"time"
Expand Down Expand Up @@ -51,15 +52,18 @@ func TestDataDogClient(t *testing.T) {
// Test that tag overrides work.
override := datadog.WithTags(map[string]string{
"tag1": "value1",
"tag2": "value2",
}).WithTags(map[string]string{
"tag1": "override",
"tag2": "value2",
"tag3": "value3",
})

actual := override.(*metrics.DataDogClient).TagMap()
expected := map[string]string{
"tag1": "override",
"tag2": "value2",
actual := override.(*metrics.DataDogClient).Tags()
expected := []string{
"tag1:override",
"tag1:value1",
"tag2:value2",
"tag3:value3",
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("Expected %v to equal %v", actual, expected)
Expand All @@ -80,3 +84,55 @@ func TestDataDogClient(t *testing.T) {

datadog.Close()
}

func Benchmark_0Tags_100Emits(b *testing.B) {
benchmarkClient(b, 0, 100, false)
}

func BenchmarkTags_5Tags_100Emits(b *testing.B) {
benchmarkClient(b, 5, 100, false)
}

func BenchmarkTags_5Tags_100Emits_WithInline(b *testing.B) {
benchmarkClient(b, 5, 100, true)
}

func BenchmarkTags_10Tags_1000Emits(b *testing.B) {
benchmarkClient(b, 10, 1000, false)
}

func BenchmarkTags_10Tags_1000Emits_WithInline(b *testing.B) {
benchmarkClient(b, 10, 1000, true)
}

func BenchmarkTags_15Tags_100Emits(b *testing.B) {
benchmarkClient(b, 15, 100, false)
}

func BenchmarkTags_15Tags_100Emits_WithInline(b *testing.B) {
benchmarkClient(b, 15, 100, true)
}

func benchmarkClient(b *testing.B, numTags, numMetrics int, inlineTags bool) {
var datadog metrics.Client
datadog = metrics.NewDataDogClient("127.0.0.1:8126", "testing")
defer datadog.Close()

tags := map[string]string{}
for i := 0; i < numTags; i++ {
tags[fmt.Sprintf("tag-%v", i)] = fmt.Sprintf("value-%v", i)
}

b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
cli := datadog.WithTags(tags)
for m := 0; m < numMetrics; m++ {
if inlineTags {
cli.WithTags(map[string]string{"a": "b"}).Histogram("histo", 123)
} else {
cli.Histogram("histo", 123)
}
}
}
}
9 changes: 6 additions & 3 deletions metrics/export_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package metrics

// TagMap returns the internal tag map from a DataDog client instance.
func (c *DataDogClient) TagMap() map[string]string {
return c.tagMap
import "sort"

// Tags returns the internal tag list from a DataDog client instance.
func (c *DataDogClient) Tags() []string {
sort.Strings(c.tags)
return c.tags
}
4 changes: 2 additions & 2 deletions metrics/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func (c *LoggerClient) Colorized() *LoggerClient {
logger: c.logger,
rate: c.rate,
colors: true,
tagMap: combine(map[string]string{}, c.tagMap),
tagMap: c.tagMap,
}
}

Expand All @@ -94,7 +94,7 @@ func (c *LoggerClient) WithRate(rate float64) Client {
logger: c.logger,
rate: rate,
colors: c.colors,
tagMap: combine(map[string]string{}, c.tagMap),
tagMap: c.tagMap,
}
}

Expand Down
2 changes: 1 addition & 1 deletion metrics/recorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ func (c *RecorderClient) WithRate(rate float64) Client {
callInfo: c.callInfo,
test: c.test,
rate: rate,
tagMap: combine(map[string]string{}, c.tagMap),
tagMap: c.tagMap,
}
}

Expand Down
1 change: 1 addition & 0 deletions metrics/recorder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

// ExpectEqual compares two values and fails if they are not deeply equal.
func ExpectEqual(t *testing.T, expected, actual interface{}) {
t.Helper()
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("Expected '%s' to be '%s'", actual, expected)
}
Expand Down
14 changes: 14 additions & 0 deletions metrics/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@ func combine(original, override map[string]string) map[string]string {
return combined
}

// cloneTagsWithMap clones the original string slice and appends the new tags in the map
func cloneTagsWithMap(original []string, newTags map[string]string) []string {
combined := make([]string, len(original)+len(newTags))
copy(combined, original)

i := len(original)
for k, v := range newTags {
combined[i] = fmt.Sprintf("%s:%s", k, v)
i++
}

return combined
}

// Converts a map to an array of strings like `key:value`.
func mapToStrings(tagMap map[string]string) []string {
tags := make([]string, 0, len(tagMap))
Expand Down