From 10c4b4fd6cc48dcdd3af93c3f6b9546dd4c084ab Mon Sep 17 00:00:00 2001 From: Martin Joehren Date: Thu, 24 Mar 2016 09:40:28 +0000 Subject: [PATCH 01/23] added general tags that should be attached to all metrics --- client.go | 6 +++--- metrics_reporter.go | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/client.go b/client.go index 3dce728..d02829e 100644 --- a/client.go +++ b/client.go @@ -114,12 +114,12 @@ func (c *Client) seriesReader(series []*Series) (io.Reader, error) { // Create a `MetricsReporter` for the given metrics reporter. The returned // reporter will not be started. -func (c *Client) Reporter(reg metrics.Registry) *MetricsReporter { - return Reporter(c, reg) +func (c *Client) Reporter(reg metrics.Registry, tags []string) *MetricsReporter { + return Reporter(c, reg, tags) } // Create a `MetricsReporter` configured to use metric's default registry. This // reporter will not be started. func (c *Client) DefaultReporter() *MetricsReporter { - return Reporter(c, metrics.DefaultRegistry) + return Reporter(c, metrics.DefaultRegistry, nil) } diff --git a/metrics_reporter.go b/metrics_reporter.go index c9b0147..23ad579 100644 --- a/metrics_reporter.go +++ b/metrics_reporter.go @@ -13,6 +13,7 @@ import ( type MetricsReporter struct { client *Client registry metrics.Registry + tags []string } // Expect the tags in the pattern @@ -23,10 +24,12 @@ var tagPattern = regexp.MustCompile("([\\w\\.]+)\\[([\\w\\W]+)\\]") // `metrics.DefaultRegistry` will suffice for the required `metrics.Registry`. // The recreated `MetricsReporter` will not be started. Invoke `go r.Start(..)` with // a `time.Duration` to enable reporting. -func Reporter(c *Client, r metrics.Registry) *MetricsReporter { +func Reporter(c *Client, r metrics.Registry, tags []string) *MetricsReporter { + return &MetricsReporter{ client: c, registry: r, + tags: tags, } } @@ -86,7 +89,7 @@ func (mr *MetricsReporter) series(t int64, name string, i interface{}) []*Series func (mr *MetricsReporter) counterSeries(t int64, id string, counter metrics.Counter) []*Series { - name, tags := splitNameAndTags(id) + name, tags := mr.splitNameAndTags(id) counter.Inc(0) return []*Series{ mr.counterI(name+".count", t, counter.Count(), tags), @@ -95,7 +98,7 @@ func (mr *MetricsReporter) counterSeries(t int64, id string, func (mr *MetricsReporter) gaugeSeries(t int64, id string, gauge metrics.Gauge) []*Series { - name, tags := splitNameAndTags(id) + name, tags := mr.splitNameAndTags(id) return []*Series{ mr.gaugeI(name+".value", t, gauge.Value(), tags), } @@ -104,7 +107,7 @@ func (mr *MetricsReporter) gaugeSeries(t int64, id string, func (mr *MetricsReporter) histogramSeries(t int64, id string, h metrics.Histogram) []*Series { ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) - name, tags := splitNameAndTags(id) + name, tags := mr.splitNameAndTags(id) return []*Series{ mr.counterI(name+".count", t, h.Count(), tags), @@ -122,7 +125,7 @@ func (mr *MetricsReporter) histogramSeries(t int64, id string, func (mr *MetricsReporter) meterSeries(t int64, id string, m metrics.Meter) []*Series { - name, tags := splitNameAndTags(id) + name, tags := mr.splitNameAndTags(id) m.Mark(0) return []*Series{ mr.counterI(name+".count", t, m.Count(), tags), @@ -136,7 +139,7 @@ func (mr *MetricsReporter) meterSeries(t int64, id string, func (mr *MetricsReporter) timerSeries(t int64, id string, m metrics.Timer) []*Series { ps := m.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) - name, tags := splitNameAndTags(id) + name, tags := mr.splitNameAndTags(id) return []*Series{ mr.counterI(name+".count", t, m.Count(), tags), @@ -207,9 +210,9 @@ func (mr *MetricsReporter) seriesI( } } -func splitNameAndTags(metric string) (string, []string) { +func (mr *MetricsReporter) splitNameAndTags(metric string) (string, []string) { if res := tagPattern.FindStringSubmatch(metric); len(res) == 3 { - return res[1], strings.Split(res[2], ",") + return res[1], append(strings.Split(res[2], ","), mr.tags...) } - return metric, make([]string, 0) + return metric, mr.tags } From d548ee2650dc637474a3f212ea2271be86c00e17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=B6hren?= Date: Wed, 11 May 2016 15:51:22 +0200 Subject: [PATCH 02/23] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2476217..ec0e102 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ along the lines of the following: ```go import( - "github.com/vistarmedia/datadog" + "github.com/esailors/go-datadog" "os" "time" ) From 86c03c211e04980d395c851ffd70890400a2769e Mon Sep 17 00:00:00 2001 From: Martin Joehren Date: Wed, 11 May 2016 15:24:02 +0000 Subject: [PATCH 03/23] added metric name func --- .gitignore | 75 ++++++++++++++++++++++++++++++++++++++++ client_test.go | 2 -- metric_name.go | 24 +++++++++++++ metrics_reporter.go | 4 +-- metrics_reporter_test.go | 2 +- name_test.go | 32 +++++++++++++++++ 6 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 .gitignore create mode 100644 metric_name.go create mode 100644 name_test.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..37ae419 --- /dev/null +++ b/.gitignore @@ -0,0 +1,75 @@ +# Created by .ignore support plugin (hsz.mobi) +### Go template +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +*.iml + +# User-specific stuff: +.idea/workspace.xml +.idea/tasks.xml +.idea/dictionaries +.idea/vcs.xml +.idea/jsLibraryMappings.xml + +# Sensitive or high-churn files: +.idea/dataSources.ids +.idea/dataSources.xml +.idea/dataSources.local.xml +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml + +# Gradle: +.idea/gradle.xml +.idea/libraries + +# Mongo Explorer plugin: +.idea/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties diff --git a/client_test.go b/client_test.go index 6d64768..d70e0dd 100644 --- a/client_test.go +++ b/client_test.go @@ -47,10 +47,8 @@ func (s *ClientSuite) TestSingleSeriesReader(c *C) { c.Check(strings.Index(body, `"tags":["one","two","three"]`), Not(Equals), -1) } - func (s *ClientSuite) TestEventsEndpoint(c *C) { client.ApiKey = "secret" c.Check(client.EventUrl(), Equals, "https://app.datadoghq.com/api/v1/events?api_key=secret") } - diff --git a/metric_name.go b/metric_name.go new file mode 100644 index 0000000..9c36695 --- /dev/null +++ b/metric_name.go @@ -0,0 +1,24 @@ +package datadog + +import ( + "bytes" + "errors" +) + +func NewMetricName(prefix string, name string, tags string) (string, error) { + if len(name) == 0 { + return "", errors.New("Metric name cannot be empty.") + } + var buffer bytes.Buffer + if len(prefix) > 0 { + buffer.WriteString(prefix) + buffer.WriteString(".") + } + buffer.WriteString(name) + if len(tags) > 0 { + buffer.WriteString("[") + buffer.WriteString(tags) + buffer.WriteString("]") + } + return buffer.String(), nil +} diff --git a/metrics_reporter.go b/metrics_reporter.go index 23ad579..d3ef4b4 100644 --- a/metrics_reporter.go +++ b/metrics_reporter.go @@ -13,7 +13,7 @@ import ( type MetricsReporter struct { client *Client registry metrics.Registry - tags []string + tags []string } // Expect the tags in the pattern @@ -29,7 +29,7 @@ func Reporter(c *Client, r metrics.Registry, tags []string) *MetricsReporter { return &MetricsReporter{ client: c, registry: r, - tags: tags, + tags: tags, } } diff --git a/metrics_reporter_test.go b/metrics_reporter_test.go index a13ef43..d3a694f 100644 --- a/metrics_reporter_test.go +++ b/metrics_reporter_test.go @@ -22,7 +22,7 @@ func (s *ReporterSuite) SetUpTest(c *C) { client = &Client{ Host: "My Host", } - reporter = &MetricsReporter{client, registry} + reporter = &MetricsReporter{client: client, registry: registry} t = time.Now() } diff --git a/name_test.go b/name_test.go new file mode 100644 index 0000000..5220570 --- /dev/null +++ b/name_test.go @@ -0,0 +1,32 @@ +package datadog + +import ( + "testing" +) + +func TestName(t *testing.T) { + var testData = []struct { + prefix string + name string + tags string + wanted string + }{ + {"", "meter", "", "meter"}, + {"prefix", "meter", "", "prefix.meter"}, + {"prefix", "meter", "tag", "prefix.meter[tag]"}, + {"", "meter", "tag", "meter[tag]"}, + {"", "meter", "tag:a,tag:b", "meter[tag:a,tag:b]"}, + } + for _, metricNameParts := range testData { + name, _ := NewMetricName(metricNameParts.prefix, metricNameParts.name, metricNameParts.tags) + if want, have := metricNameParts.wanted, name; want != have { + t.Errorf("%s [wanted] != %s [have]", want, have) + } + } +} + +func TestMissingName(t *testing.T) { + if _, err := NewMetricName("", "", ""); err == nil { + t.Error("An empty name must return an error.") + } +} From be30a89727e7d0072415d5b6fa57ecbe620cfb0c Mon Sep 17 00:00:00 2001 From: Martin Joehren Date: Wed, 11 May 2016 16:07:15 +0000 Subject: [PATCH 04/23] added unchecked create name version --- metric_name.go | 9 +++++++-- name_test.go => metric_name_test.go | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) rename name_test.go => metric_name_test.go (79%) diff --git a/metric_name.go b/metric_name.go index 9c36695..aeb040c 100644 --- a/metric_name.go +++ b/metric_name.go @@ -5,10 +5,15 @@ import ( "errors" ) -func NewMetricName(prefix string, name string, tags string) (string, error) { +func NewCheckedMetricName(prefix string, name string, tags string) (string, error) { if len(name) == 0 { return "", errors.New("Metric name cannot be empty.") } + + return NewMetricName(prefix, name, tags), nil +} + +func NewMetricName(prefix string, name string, tags string) string { var buffer bytes.Buffer if len(prefix) > 0 { buffer.WriteString(prefix) @@ -20,5 +25,5 @@ func NewMetricName(prefix string, name string, tags string) (string, error) { buffer.WriteString(tags) buffer.WriteString("]") } - return buffer.String(), nil + return buffer.String() } diff --git a/name_test.go b/metric_name_test.go similarity index 79% rename from name_test.go rename to metric_name_test.go index 5220570..e33e4bc 100644 --- a/name_test.go +++ b/metric_name_test.go @@ -18,7 +18,7 @@ func TestName(t *testing.T) { {"", "meter", "tag:a,tag:b", "meter[tag:a,tag:b]"}, } for _, metricNameParts := range testData { - name, _ := NewMetricName(metricNameParts.prefix, metricNameParts.name, metricNameParts.tags) + name, _ := NewCheckedMetricName(metricNameParts.prefix, metricNameParts.name, metricNameParts.tags) if want, have := metricNameParts.wanted, name; want != have { t.Errorf("%s [wanted] != %s [have]", want, have) } @@ -26,7 +26,7 @@ func TestName(t *testing.T) { } func TestMissingName(t *testing.T) { - if _, err := NewMetricName("", "", ""); err == nil { + if _, err := NewCheckedMetricName("", "", ""); err == nil { t.Error("An empty name must return an error.") } } From 757dbaffb31fa44b525647d9dadc5835a0994e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=B6hren?= Date: Wed, 11 May 2016 19:45:47 +0200 Subject: [PATCH 05/23] Create .travis.yml --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..4a69f88 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: go + +go: + - 1.5 + - 1.6 + +script: go test -v -tags . + +sudo: false From 626e91883190c47f792431777356fe23643412b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=B6hren?= Date: Wed, 11 May 2016 19:47:55 +0200 Subject: [PATCH 06/23] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ec0e102..265884d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +[![Build Status](https://travis-ci.org/eSailors/go-datadog.svg?branch=master)](https://travis-ci.org/eSailors/go-datadog) # Go Datadog Simple [Go](http://golang.org/) interface to the [Datadog API](http://docs.datadoghq.com/api/). From 3a65b601807b284ef18d38789ffdcc65d2df7773 Mon Sep 17 00:00:00 2001 From: Martin Joehren Date: Tue, 24 Jan 2017 10:31:03 +0000 Subject: [PATCH 07/23] log complete response on error --- client.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client.go b/client.go index d02829e..d74e36b 100644 --- a/client.go +++ b/client.go @@ -5,9 +5,10 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/rcrowley/go-metrics" "io" "net/http" + + "github.com/rcrowley/go-metrics" ) const ( @@ -95,7 +96,7 @@ func (c *Client) PostSeries(series []*Series) (err error) { } defer resp.Body.Close() if !(resp.StatusCode == 200 || resp.StatusCode == 202) { - return fmt.Errorf("Bad Datadog response: '%s'", resp.Status) + return fmt.Errorf("Bad Datadog response: '%+v'", resp) } return } From f50ae93817c978b64e625eb5da655d59250fc05c Mon Sep 17 00:00:00 2001 From: Oliver Bestmann Date: Mon, 30 Jan 2017 10:01:02 +0000 Subject: [PATCH 08/23] Send metrics in chunks of around 2mb. --- client.go | 99 +++++++++++++++++++++++++++++---------------- metrics_reporter.go | 48 +++++++++------------- 2 files changed, 85 insertions(+), 62 deletions(-) diff --git a/client.go b/client.go index d74e36b..b5b634e 100644 --- a/client.go +++ b/client.go @@ -2,13 +2,14 @@ package datadog import ( - "bytes" "encoding/json" "fmt" - "io" "net/http" + "bytes" "github.com/rcrowley/go-metrics" + "io" + "io/ioutil" ) const ( @@ -24,7 +25,7 @@ type Client struct { } type seriesMessage struct { - Series []*Series `json:"series,omitempty"` + Series []json.RawMessage `json:"series,omitempty"` } type Series struct { @@ -65,52 +66,65 @@ func (c *Client) EventUrl() string { } func (c *Client) PostEvent(event *Event) (err error) { - bs, err := json.Marshal(event) + body, err := json.Marshal(event) if err != nil { return err } - resp, err := http.Post(c.EventUrl(), CONTENT_TYPE, bytes.NewBuffer(bs)) - if err != nil { - return err - } - - defer resp.Body.Close() - if !(resp.StatusCode == 200 || resp.StatusCode == 202) { - return fmt.Errorf("Bad Datadog response: '%s'", resp.Status) - } - return + return c.doRequest(c.EventUrl(), body) } +const messageChunkSize = 2 * 1024 * 1024 + // Posts an array of series data to the Datadog API. The API expects an object, // not an array, so it will be wrapped in a `seriesMessage` with a single // `series` field. -func (c *Client) PostSeries(series []*Series) (err error) { - body, err := c.seriesReader(series) - if err != nil { - return err +// +// If the slice contains too many series, the message will be split into +// multiple chunks of around 2mb each. +// +func (c *Client) PostSeries(series []*Series, reg metrics.Registry) error { + var approxTotalSize int + var encodedSeries []json.RawMessage + + for _, serie := range series { + // encode series to json + jsonSerie, err := json.Marshal(serie) + if err != nil { + return err + } + + encoded := json.RawMessage(jsonSerie) + + // count bytes of this message + approxTotalSize += len(encoded) + encodedSeries = append(encodedSeries, encoded) + + if approxTotalSize > messageChunkSize { + if err := c.sendEncodedSeries(encodedSeries); err != nil { + return err + } + + // reset and start to collect the next chunk + encodedSeries = encodedSeries[:0] + approxTotalSize = 0 + } } - resp, err := http.Post(c.SeriesUrl(), CONTENT_TYPE, body) - if err != nil { - return err - } - defer resp.Body.Close() - if !(resp.StatusCode == 200 || resp.StatusCode == 202) { - return fmt.Errorf("Bad Datadog response: '%+v'", resp) + + if len(encodedSeries) > 0 { + return c.sendEncodedSeries(encodedSeries) } - return + + return nil } -// Serializes an array of `Series` to JSON. The array will be wrapped in a -// `seriesMessage`, changing the serialized type from an array to an object with -// a single `series` field. -func (c *Client) seriesReader(series []*Series) (io.Reader, error) { - msg := &seriesMessage{series} - bs, err := json.Marshal(msg) +func (c *Client) sendEncodedSeries(series []json.RawMessage) error { + body, err := json.Marshal(seriesMessage{series}) if err != nil { - return nil, err + return err } - return bytes.NewBuffer(bs), nil + + return c.doRequest(c.SeriesUrl(), body) } // Create a `MetricsReporter` for the given metrics reporter. The returned @@ -124,3 +138,20 @@ func (c *Client) Reporter(reg metrics.Registry, tags []string) *MetricsReporter func (c *Client) DefaultReporter() *MetricsReporter { return Reporter(c, metrics.DefaultRegistry, nil) } + +func (c *Client) doRequest(url string, body []byte) (err error) { + resp, err := http.Post(c.SeriesUrl(), CONTENT_TYPE, bytes.NewReader(body)) + if err != nil { + return err + } + + // for keep-alive we ensure that the response-body is read. + defer io.Copy(ioutil.Discard, resp.Body) + defer resp.Body.Close() + + if !(resp.StatusCode == 200 || resp.StatusCode == 202) { + return fmt.Errorf("Bad Datadog response: '%+v'", resp) + } + + return nil +} diff --git a/metrics_reporter.go b/metrics_reporter.go index d3ef4b4..39d30ab 100644 --- a/metrics_reporter.go +++ b/metrics_reporter.go @@ -52,7 +52,7 @@ func (mr *MetricsReporter) Start(d time.Duration) { // POST a single series report to the Datadog API. A 200 or 202 is expected for // this to complete without error. func (mr *MetricsReporter) Report() error { - return mr.client.PostSeries(mr.Series()) + return mr.client.PostSeries(mr.Series(), mr.registry) } // For each metric assocaited with the current Registry, convert it to a @@ -62,8 +62,11 @@ func (mr *MetricsReporter) Series() []*Series { now := time.Now().Unix() series := make([]*Series, 0) mr.registry.Each(func(name string, metric interface{}) { - series = append(series, mr.series(now, name, metric)...) + s := mr.series(now, name, metric) + series = append(series, s...) }) + + metrics.GetOrRegisterGauge("metrics.series.count", mr.registry).Update(int64(len(series))) return series } @@ -74,21 +77,20 @@ func (mr *MetricsReporter) series(t int64, name string, i interface{}) []*Series case metrics.Counter: return mr.counterSeries(t, name, m) case metrics.Gauge: - return mr.gaugeSeries(t, name, m) + return mr.gaugeSeries(t, name, m.Snapshot()) case metrics.Healthcheck: - // TODO: Not implemented + // TODO: Not implemented case metrics.Histogram: - return mr.histogramSeries(t, name, m) + return mr.histogramSeries(t, name, m.Snapshot()) case metrics.Meter: - return mr.meterSeries(t, name, m) + return mr.meterSeries(t, name, m.Snapshot()) case metrics.Timer: - return mr.timerSeries(t, name, m) + return mr.timerSeries(t, name, m.Snapshot()) } return nil } -func (mr *MetricsReporter) counterSeries(t int64, id string, - counter metrics.Counter) []*Series { +func (mr *MetricsReporter) counterSeries(t int64, id string, counter metrics.Counter) []*Series { name, tags := mr.splitNameAndTags(id) counter.Inc(0) return []*Series{ @@ -96,16 +98,14 @@ func (mr *MetricsReporter) counterSeries(t int64, id string, } } -func (mr *MetricsReporter) gaugeSeries(t int64, id string, - gauge metrics.Gauge) []*Series { +func (mr *MetricsReporter) gaugeSeries(t int64, id string, gauge metrics.Gauge) []*Series { name, tags := mr.splitNameAndTags(id) return []*Series{ mr.gaugeI(name+".value", t, gauge.Value(), tags), } } -func (mr *MetricsReporter) histogramSeries(t int64, id string, - h metrics.Histogram) []*Series { +func (mr *MetricsReporter) histogramSeries(t int64, id string, h metrics.Histogram) []*Series { ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) name, tags := mr.splitNameAndTags(id) @@ -123,10 +123,8 @@ func (mr *MetricsReporter) histogramSeries(t int64, id string, } } -func (mr *MetricsReporter) meterSeries(t int64, id string, - m metrics.Meter) []*Series { +func (mr *MetricsReporter) meterSeries(t int64, id string, m metrics.Meter) []*Series { name, tags := mr.splitNameAndTags(id) - m.Mark(0) return []*Series{ mr.counterI(name+".count", t, m.Count(), tags), mr.counterF(name+".rate.1min", t, m.Rate1(), tags), @@ -136,8 +134,7 @@ func (mr *MetricsReporter) meterSeries(t int64, id string, } } -func (mr *MetricsReporter) timerSeries(t int64, id string, - m metrics.Timer) []*Series { +func (mr *MetricsReporter) timerSeries(t int64, id string, m metrics.Timer) []*Series { ps := m.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) name, tags := mr.splitNameAndTags(id) @@ -173,23 +170,19 @@ func millisF(nanos float64) float64 { // return int64(nanos) / int64(time.Millisecond) // } -func (mr *MetricsReporter) counterF( - metric string, t int64, v float64, tags []string) *Series { +func (mr *MetricsReporter) counterF(metric string, t int64, v float64, tags []string) *Series { return mr.seriesF(metric, "counter", t, v, tags) } -func (mr *MetricsReporter) counterI( - metric string, t int64, v int64, tags []string) *Series { +func (mr *MetricsReporter) counterI(metric string, t int64, v int64, tags []string) *Series { return mr.seriesI(metric, "counter", t, v, tags) } -func (mr *MetricsReporter) gaugeI( - metric string, t int64, v int64, tags []string) *Series { +func (mr *MetricsReporter) gaugeI(metric string, t int64, v int64, tags []string) *Series { return mr.seriesI(metric, "gauge", t, v, tags) } -func (mr *MetricsReporter) seriesF( - metric, typ string, t int64, v float64, tags []string) *Series { +func (mr *MetricsReporter) seriesF(metric, typ string, t int64, v float64, tags []string) *Series { return &Series{ Metric: metric, Points: [][2]interface{}{[2]interface{}{t, v}}, @@ -199,8 +192,7 @@ func (mr *MetricsReporter) seriesF( } } -func (mr *MetricsReporter) seriesI( - metric, typ string, t int64, v int64, tags []string) *Series { +func (mr *MetricsReporter) seriesI(metric, typ string, t int64, v int64, tags []string) *Series { return &Series{ Metric: metric, Points: [][2]interface{}{[2]interface{}{t, v}}, From eb29b8cca849d523b9be68bd992ed6bd8d1e5143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=B6hren?= Date: Fri, 17 Mar 2017 19:22:23 +0100 Subject: [PATCH 09/23] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4a69f88..e8f950d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,6 @@ go: - 1.5 - 1.6 -script: go test -v -tags . +script: go get github.com/rcrowley/go-metrics && go test -v -tags . sudo: false From 7390961dff8abfab77e6a85e85203789810109b1 Mon Sep 17 00:00:00 2001 From: Martin Joehren Date: Fri, 17 Mar 2017 18:54:55 +0000 Subject: [PATCH 10/23] fix test --- client.go | 2 +- client_test.go | 27 +-------------------------- metric_name.go | 2 +- metric_name_test.go | 2 +- metrics_reporter.go | 2 +- metrics_reporter_test.go | 2 +- 6 files changed, 6 insertions(+), 31 deletions(-) diff --git a/client.go b/client.go index b5b634e..88f1c5d 100644 --- a/client.go +++ b/client.go @@ -1,5 +1,5 @@ // Simple client to the [Datadog API](http://docs.datadoghq.com/api/). -package datadog +package datadog import ( "encoding/json" diff --git a/client_test.go b/client_test.go index d70e0dd..ccbc9e3 100644 --- a/client_test.go +++ b/client_test.go @@ -1,9 +1,7 @@ package datadog import ( - "io/ioutil" - . "launchpad.net/gocheck" - "strings" + . "github.com/go-check/check" "testing" ) @@ -24,29 +22,6 @@ func (s *ClientSuite) TestSeriesEndpoint(c *C) { "https://app.datadoghq.com/api/v1/series?api_key=secret") } -func (s *ClientSuite) TestSingleSeriesReader(c *C) { - series := &Series{ - Metric: "foo.bar.baz", - Points: [][2]interface{}{[2]interface{}{1346340794, 66.6}}, - Type: "gauge", - Host: "hostname", - Tags: []string{"one", "two", "three"}, - } - - reader, err := client.seriesReader([]*Series{series}) - c.Check(err, IsNil) - - b, err := ioutil.ReadAll(reader) - c.Check(err, IsNil) - - body := string(b) - c.Check(strings.Index(body, `"metric":"foo.bar.baz"`), Not(Equals), -1) - c.Check(strings.Index(body, `"points":[[1346340794,66.6]]`), Not(Equals), -1) - c.Check(strings.Index(body, `"type":"gauge"`), Not(Equals), -1) - c.Check(strings.Index(body, `"host":"hostname"`), Not(Equals), -1) - c.Check(strings.Index(body, `"tags":["one","two","three"]`), Not(Equals), -1) -} - func (s *ClientSuite) TestEventsEndpoint(c *C) { client.ApiKey = "secret" c.Check(client.EventUrl(), Equals, diff --git a/metric_name.go b/metric_name.go index aeb040c..973d940 100644 --- a/metric_name.go +++ b/metric_name.go @@ -1,4 +1,4 @@ -package datadog +package datadog import ( "bytes" diff --git a/metric_name_test.go b/metric_name_test.go index e33e4bc..3bf241b 100644 --- a/metric_name_test.go +++ b/metric_name_test.go @@ -1,4 +1,4 @@ -package datadog +package datadog import ( "testing" diff --git a/metrics_reporter.go b/metrics_reporter.go index 39d30ab..792967c 100644 --- a/metrics_reporter.go +++ b/metrics_reporter.go @@ -1,6 +1,6 @@ // Datadog reporter for the [go-metrics](https://github.com/rcrowley/go-metrics) // library. -package datadog +package datadog import ( "github.com/rcrowley/go-metrics" diff --git a/metrics_reporter_test.go b/metrics_reporter_test.go index d3a694f..359a1ef 100644 --- a/metrics_reporter_test.go +++ b/metrics_reporter_test.go @@ -2,7 +2,7 @@ package datadog import ( "github.com/rcrowley/go-metrics" - . "launchpad.net/gocheck" + . "github.com/go-check/check" "time" ) From 46c2a42f156bee939bbc01bb6174b86829ca74df Mon Sep 17 00:00:00 2001 From: Martin Joehren Date: Fri, 17 Mar 2017 18:56:16 +0000 Subject: [PATCH 11/23] added go get to travis --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e8f950d..4ced450 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,8 @@ go: - 1.5 - 1.6 -script: go get github.com/rcrowley/go-metrics && go test -v -tags . +script: go get github.com/go-check/check && \ + go get github.com/rcrowley/go-metrics && \ + go test -v -tags . sudo: false From acdce21333147c2a66d1f61f79f7143e05060e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=B6hren?= Date: Fri, 17 Mar 2017 20:00:43 +0100 Subject: [PATCH 12/23] Update .travis.yml --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4ced450..db05a88 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,6 @@ go: - 1.5 - 1.6 -script: go get github.com/go-check/check && \ - go get github.com/rcrowley/go-metrics && \ - go test -v -tags . +script: go get github.com/go-check/check && go get github.com/rcrowley/go-metrics && go test -v -tags . sudo: false From 030017765429f2d98be0c06390b59a5573e81cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=B6hren?= Date: Fri, 17 Mar 2017 20:01:40 +0100 Subject: [PATCH 13/23] Update .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index db05a88..150ad69 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: go go: - - 1.5 - - 1.6 + - 1.7 + - 1.8 script: go get github.com/go-check/check && go get github.com/rcrowley/go-metrics && go test -v -tags . From 289f416d3143030b6d5cfd1bd469b11a0ac9d9e9 Mon Sep 17 00:00:00 2001 From: Martin Joehren Date: Fri, 17 Mar 2017 19:14:26 +0000 Subject: [PATCH 14/23] fix order in test --- metrics_reporter_test.go | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/metrics_reporter_test.go b/metrics_reporter_test.go index 359a1ef..a43efab 100644 --- a/metrics_reporter_test.go +++ b/metrics_reporter_test.go @@ -38,12 +38,21 @@ func (s *ReporterSuite) TestSimpleReport(c *C) { series := reporter.Series() c.Check(series, HasLen, 6) - c.Check(series[0].Metric, Equals, "my.counter.count") - c.Check(series[1].Metric, Equals, "my.meter.count") - c.Check(series[2].Metric, Equals, "my.meter.rate.1min") - c.Check(series[3].Metric, Equals, "my.meter.rate.5min") - c.Check(series[4].Metric, Equals, "my.meter.rate.15min") - c.Check(series[5].Metric, Equals, "my.meter.rate.mean") + c.Check(contains(series, "my.counter.count"), Equals, true) + c.Check(contains(series, "my.meter.count"), Equals, true) + c.Check(contains(series, "my.meter.rate.1min"), Equals, true) + c.Check(contains(series, "my.meter.rate.5min"), Equals, true) + c.Check(contains(series, "my.meter.rate.15min"), Equals, true) + c.Check(contains(series, "my.meter.rate.mean"), Equals, true) +} + +func contains(series []*Series, metricName string) bool { + for _, m := range series { + if m.Metric == metricName { + return true + } + } + return false } func (_ *ReporterSuite) TestCounterSeries(c *C) { From c9c580261da3218db3909c1a9cd78f9f09245ae3 Mon Sep 17 00:00:00 2001 From: Oliver Bestmann Date: Tue, 11 Sep 2018 07:14:35 +0000 Subject: [PATCH 15/23] Add go modules suport and support for Gauge64 --- .gitignore | 2 ++ client.go | 10 ++++--- go.mod | 7 +++++ go.sum | 9 ++++++ metric_name.go | 6 ++-- metric_name_test.go | 2 +- metrics_reporter.go | 64 ++++++++++++++++++++++------------------ metrics_reporter_test.go | 10 +++---- 8 files changed, 69 insertions(+), 41 deletions(-) create mode 100644 go.mod create mode 100644 go.sum diff --git a/.gitignore b/.gitignore index 37ae419..3c898ca 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,8 @@ _testmain.go # IntelliJ /out/ +/.idea +*.iml # mpeltonen/sbt-idea plugin .idea_modules/ diff --git a/client.go b/client.go index 88f1c5d..61b0f7b 100644 --- a/client.go +++ b/client.go @@ -1,10 +1,11 @@ // Simple client to the [Datadog API](http://docs.datadoghq.com/api/). -package datadog +package datadog import ( "encoding/json" "fmt" "net/http" + "net/http/httputil" "bytes" "github.com/rcrowley/go-metrics" @@ -83,7 +84,7 @@ const messageChunkSize = 2 * 1024 * 1024 // If the slice contains too many series, the message will be split into // multiple chunks of around 2mb each. // -func (c *Client) PostSeries(series []*Series, reg metrics.Registry) error { +func (c *Client) PostSeries(series []Series, reg metrics.Registry) error { var approxTotalSize int var encodedSeries []json.RawMessage @@ -149,8 +150,9 @@ func (c *Client) doRequest(url string, body []byte) (err error) { defer io.Copy(ioutil.Discard, resp.Body) defer resp.Body.Close() - if !(resp.StatusCode == 200 || resp.StatusCode == 202) { - return fmt.Errorf("Bad Datadog response: '%+v'", resp) + if resp.StatusCode/100 != 200 { + dump, _ := httputil.DumpResponse(resp, true) + return fmt.Errorf("bad datadog response: \n%s", string(dump)) } return nil diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..9a10cf0 --- /dev/null +++ b/go.mod @@ -0,0 +1,7 @@ +module github.com/eSailors/go-datadog + +require ( + github.com/go-check/check v0.0.0-20180628173108-788fd7840127 + github.com/kr/pretty v0.1.0 // indirect + github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..8c0959a --- /dev/null +++ b/go.sum @@ -0,0 +1,9 @@ +github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 h1:nkcn14uNmFEuGCb2mBZbBb24RdNRL08b/wb+xBOYpuk= +github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= diff --git a/metric_name.go b/metric_name.go index 973d940..8509aab 100644 --- a/metric_name.go +++ b/metric_name.go @@ -1,8 +1,8 @@ -package datadog +package datadog import ( - "bytes" "errors" + "strings" ) func NewCheckedMetricName(prefix string, name string, tags string) (string, error) { @@ -14,7 +14,7 @@ func NewCheckedMetricName(prefix string, name string, tags string) (string, erro } func NewMetricName(prefix string, name string, tags string) string { - var buffer bytes.Buffer + var buffer strings.Builder if len(prefix) > 0 { buffer.WriteString(prefix) buffer.WriteString(".") diff --git a/metric_name_test.go b/metric_name_test.go index 3bf241b..e33e4bc 100644 --- a/metric_name_test.go +++ b/metric_name_test.go @@ -1,4 +1,4 @@ -package datadog +package datadog import ( "testing" diff --git a/metrics_reporter.go b/metrics_reporter.go index 792967c..2cfe8e0 100644 --- a/metrics_reporter.go +++ b/metrics_reporter.go @@ -1,6 +1,6 @@ // Datadog reporter for the [go-metrics](https://github.com/rcrowley/go-metrics) // library. -package datadog +package datadog import ( "github.com/rcrowley/go-metrics" @@ -25,7 +25,6 @@ var tagPattern = regexp.MustCompile("([\\w\\.]+)\\[([\\w\\W]+)\\]") // The recreated `MetricsReporter` will not be started. Invoke `go r.Start(..)` with // a `time.Duration` to enable reporting. func Reporter(c *Client, r metrics.Registry, tags []string) *MetricsReporter { - return &MetricsReporter{ client: c, registry: r, @@ -58,9 +57,9 @@ func (mr *MetricsReporter) Report() error { // For each metric assocaited with the current Registry, convert it to a // `Series` message, and return them all as a single array. The series messages // will have the current hostname of the `Client`. -func (mr *MetricsReporter) Series() []*Series { +func (mr *MetricsReporter) Series() []Series { now := time.Now().Unix() - series := make([]*Series, 0) + series := make([]Series, 0) mr.registry.Each(func(name string, metric interface{}) { s := mr.series(now, name, metric) series = append(series, s...) @@ -72,12 +71,14 @@ func (mr *MetricsReporter) Series() []*Series { // Switch through the known types of meters delegating out to specific methods. // If an unknown metric is encountered, this will return nil. -func (mr *MetricsReporter) series(t int64, name string, i interface{}) []*Series { +func (mr *MetricsReporter) series(t int64, name string, i interface{}) []Series { switch m := i.(type) { case metrics.Counter: return mr.counterSeries(t, name, m) case metrics.Gauge: return mr.gaugeSeries(t, name, m.Snapshot()) + case metrics.GaugeFloat64: + return mr.gauge64Series(t, name, m.Snapshot()) case metrics.Healthcheck: // TODO: Not implemented case metrics.Histogram: @@ -90,26 +91,33 @@ func (mr *MetricsReporter) series(t int64, name string, i interface{}) []*Series return nil } -func (mr *MetricsReporter) counterSeries(t int64, id string, counter metrics.Counter) []*Series { +func (mr *MetricsReporter) counterSeries(t int64, id string, counter metrics.Counter) []Series { name, tags := mr.splitNameAndTags(id) counter.Inc(0) - return []*Series{ + return []Series{ mr.counterI(name+".count", t, counter.Count(), tags), } } -func (mr *MetricsReporter) gaugeSeries(t int64, id string, gauge metrics.Gauge) []*Series { +func (mr *MetricsReporter) gaugeSeries(t int64, id string, gauge metrics.Gauge) []Series { name, tags := mr.splitNameAndTags(id) - return []*Series{ + return []Series{ mr.gaugeI(name+".value", t, gauge.Value(), tags), } } -func (mr *MetricsReporter) histogramSeries(t int64, id string, h metrics.Histogram) []*Series { +func (mr *MetricsReporter) gauge64Series(t int64, id string, gauge metrics.GaugeFloat64) []Series { + name, tags := mr.splitNameAndTags(id) + return []Series{ + mr.gaugeF(name+".value", t, gauge.Value(), tags), + } +} + +func (mr *MetricsReporter) histogramSeries(t int64, id string, h metrics.Histogram) []Series { ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) name, tags := mr.splitNameAndTags(id) - return []*Series{ + return []Series{ mr.counterI(name+".count", t, h.Count(), tags), mr.counterI(name+".min", t, h.Min(), tags), mr.counterI(name+".max", t, h.Max(), tags), @@ -123,9 +131,9 @@ func (mr *MetricsReporter) histogramSeries(t int64, id string, h metrics.Histogr } } -func (mr *MetricsReporter) meterSeries(t int64, id string, m metrics.Meter) []*Series { +func (mr *MetricsReporter) meterSeries(t int64, id string, m metrics.Meter) []Series { name, tags := mr.splitNameAndTags(id) - return []*Series{ + return []Series{ mr.counterI(name+".count", t, m.Count(), tags), mr.counterF(name+".rate.1min", t, m.Rate1(), tags), mr.counterF(name+".rate.5min", t, m.Rate5(), tags), @@ -134,11 +142,11 @@ func (mr *MetricsReporter) meterSeries(t int64, id string, m metrics.Meter) []*S } } -func (mr *MetricsReporter) timerSeries(t int64, id string, m metrics.Timer) []*Series { +func (mr *MetricsReporter) timerSeries(t int64, id string, m metrics.Timer) []Series { ps := m.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999}) name, tags := mr.splitNameAndTags(id) - return []*Series{ + return []Series{ mr.counterI(name+".count", t, m.Count(), tags), mr.counterF(name+".min", t, millisI(m.Min()), tags), mr.counterF(name+".max", t, millisI(m.Max()), tags), @@ -166,36 +174,36 @@ func millisF(nanos float64) float64 { return nanos / float64(time.Millisecond) } -// func floatMs(nanos float64) int64 { -// return int64(nanos) / int64(time.Millisecond) -// } - -func (mr *MetricsReporter) counterF(metric string, t int64, v float64, tags []string) *Series { +func (mr *MetricsReporter) counterF(metric string, t int64, v float64, tags []string) Series { return mr.seriesF(metric, "counter", t, v, tags) } -func (mr *MetricsReporter) counterI(metric string, t int64, v int64, tags []string) *Series { +func (mr *MetricsReporter) counterI(metric string, t int64, v int64, tags []string) Series { return mr.seriesI(metric, "counter", t, v, tags) } -func (mr *MetricsReporter) gaugeI(metric string, t int64, v int64, tags []string) *Series { +func (mr *MetricsReporter) gaugeI(metric string, t int64, v int64, tags []string) Series { return mr.seriesI(metric, "gauge", t, v, tags) } -func (mr *MetricsReporter) seriesF(metric, typ string, t int64, v float64, tags []string) *Series { - return &Series{ +func (mr *MetricsReporter) gaugeF(metric string, t int64, v float64, tags []string) Series { + return mr.seriesF(metric, "gauge", t, v, tags) +} + +func (mr *MetricsReporter) seriesF(metric, typ string, t int64, v float64, tags []string) Series { + return Series{ Metric: metric, - Points: [][2]interface{}{[2]interface{}{t, v}}, + Points: [][2]interface{}{{t, v}}, Type: typ, Host: mr.client.Host, Tags: tags, } } -func (mr *MetricsReporter) seriesI(metric, typ string, t int64, v int64, tags []string) *Series { - return &Series{ +func (mr *MetricsReporter) seriesI(metric, typ string, t int64, v int64, tags []string) Series { + return Series{ Metric: metric, - Points: [][2]interface{}{[2]interface{}{t, v}}, + Points: [][2]interface{}{{t, v}}, Type: typ, Host: mr.client.Host, Tags: tags, diff --git a/metrics_reporter_test.go b/metrics_reporter_test.go index a43efab..cb74594 100644 --- a/metrics_reporter_test.go +++ b/metrics_reporter_test.go @@ -1,8 +1,8 @@ package datadog import ( - "github.com/rcrowley/go-metrics" . "github.com/go-check/check" + "github.com/rcrowley/go-metrics" "time" ) @@ -46,11 +46,11 @@ func (s *ReporterSuite) TestSimpleReport(c *C) { c.Check(contains(series, "my.meter.rate.mean"), Equals, true) } -func contains(series []*Series, metricName string) bool { +func contains(series []Series, metricName string) bool { for _, m := range series { - if m.Metric == metricName { - return true - } + if m.Metric == metricName { + return true + } } return false } From 92fa5e29846cce7963a95e33e9f632575a73d58a Mon Sep 17 00:00:00 2001 From: oliverbestmann Date: Tue, 11 Sep 2018 09:56:54 +0200 Subject: [PATCH 16/23] Update .travis.yml --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 150ad69..fb889ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,10 @@ language: go go: - - 1.7 - - 1.8 + - 1.11 -script: go get github.com/go-check/check && go get github.com/rcrowley/go-metrics && go test -v -tags . +script: + - go get github.com/go-check/check + - env GO111MODULE=on go test -v -tags . sudo: false From f9d38b7354941f7facdfccdf1891b67a8c98ec2a Mon Sep 17 00:00:00 2001 From: Oliver Bestmann Date: Tue, 11 Sep 2018 09:12:11 +0000 Subject: [PATCH 17/23] Fix status check --- client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.go b/client.go index 61b0f7b..e41c918 100644 --- a/client.go +++ b/client.go @@ -150,7 +150,7 @@ func (c *Client) doRequest(url string, body []byte) (err error) { defer io.Copy(ioutil.Discard, resp.Body) defer resp.Body.Close() - if resp.StatusCode/100 != 200 { + if resp.StatusCode/100 != 2 { dump, _ := httputil.DumpResponse(resp, true) return fmt.Errorf("bad datadog response: \n%s", string(dump)) } From f41dd3f51aa5d361c668dfaeb066e47d6424543f Mon Sep 17 00:00:00 2001 From: Oliver Bestmann Date: Mon, 17 Sep 2018 06:23:19 +0000 Subject: [PATCH 18/23] Improve logging of failed request/response cycle --- client.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/client.go b/client.go index e41c918..7b1d42f 100644 --- a/client.go +++ b/client.go @@ -141,7 +141,13 @@ func (c *Client) DefaultReporter() *MetricsReporter { } func (c *Client) doRequest(url string, body []byte) (err error) { - resp, err := http.Post(c.SeriesUrl(), CONTENT_TYPE, bytes.NewReader(body)) + req, err := http.NewRequest("POST", c.SeriesUrl(), bytes.NewReader(body)) + if err != nil { + return fmt.Errorf("building request: %s", err) + } + + // now execute the request + resp, err := http.DefaultClient.Do(req) if err != nil { return err } @@ -151,8 +157,9 @@ func (c *Client) doRequest(url string, body []byte) (err error) { defer resp.Body.Close() if resp.StatusCode/100 != 2 { - dump, _ := httputil.DumpResponse(resp, true) - return fmt.Errorf("bad datadog response: \n%s", string(dump)) + dumpReq, _ := httputil.DumpRequest(req, true) + dumpRes, _ := httputil.DumpResponse(resp, true) + return fmt.Errorf("bad datadog request and response:\n%s\n%s", string(dumpReq), string(dumpRes)) } return nil From 9ee40d75a353ff8c193cc6b16b9dc2332fe1a42d Mon Sep 17 00:00:00 2001 From: Oliver Bestmann Date: Mon, 17 Sep 2018 06:59:31 +0000 Subject: [PATCH 19/23] Improve logging of request body --- client.go | 5 +++-- metrics_reporter.go | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/client.go b/client.go index 7b1d42f..3f85088 100644 --- a/client.go +++ b/client.go @@ -157,9 +157,10 @@ func (c *Client) doRequest(url string, body []byte) (err error) { defer resp.Body.Close() if resp.StatusCode/100 != 2 { - dumpReq, _ := httputil.DumpRequest(req, true) + dumpReq, _ := httputil.DumpRequest(req, false) dumpRes, _ := httputil.DumpResponse(resp, true) - return fmt.Errorf("bad datadog request and response:\n%s\n%s", string(dumpReq), string(dumpRes)) + return fmt.Errorf("bad datadog request and response:\n%s\n%s\n\n%s", + string(dumpReq), string(body), string(dumpRes)) } return nil diff --git a/metrics_reporter.go b/metrics_reporter.go index 2cfe8e0..ba96ac0 100644 --- a/metrics_reporter.go +++ b/metrics_reporter.go @@ -54,12 +54,13 @@ func (mr *MetricsReporter) Report() error { return mr.client.PostSeries(mr.Series(), mr.registry) } -// For each metric assocaited with the current Registry, convert it to a +// For each metric associated with the current Registry, convert it to a // `Series` message, and return them all as a single array. The series messages // will have the current hostname of the `Client`. func (mr *MetricsReporter) Series() []Series { now := time.Now().Unix() - series := make([]Series, 0) + + var series []Series mr.registry.Each(func(name string, metric interface{}) { s := mr.series(now, name, metric) series = append(series, s...) From 19ffa7a6ee23b6b59e6d3cdd35a221be8f252e1b Mon Sep 17 00:00:00 2001 From: Oliver Bestmann Date: Mon, 17 Sep 2018 07:01:56 +0000 Subject: [PATCH 20/23] Improve datadog request headers --- client.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client.go b/client.go index 3f85088..15b74b4 100644 --- a/client.go +++ b/client.go @@ -146,6 +146,9 @@ func (c *Client) doRequest(url string, body []byte) (err error) { return fmt.Errorf("building request: %s", err) } + req.ContentLength = int64(len(body)) + req.Header.Set("Content-Type", "application/json") + // now execute the request resp, err := http.DefaultClient.Do(req) if err != nil { From ae9a6803268c11a6eb60371a63c830a2acb122f9 Mon Sep 17 00:00:00 2001 From: Oliver Bestmann Date: Mon, 17 Sep 2018 07:34:20 +0000 Subject: [PATCH 21/23] Revert "Improve logging of request body" This reverts commit 9ee40d75a353ff8c193cc6b16b9dc2332fe1a42d. --- client.go | 5 ++--- metrics_reporter.go | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/client.go b/client.go index 15b74b4..9d53ec3 100644 --- a/client.go +++ b/client.go @@ -160,10 +160,9 @@ func (c *Client) doRequest(url string, body []byte) (err error) { defer resp.Body.Close() if resp.StatusCode/100 != 2 { - dumpReq, _ := httputil.DumpRequest(req, false) + dumpReq, _ := httputil.DumpRequest(req, true) dumpRes, _ := httputil.DumpResponse(resp, true) - return fmt.Errorf("bad datadog request and response:\n%s\n%s\n\n%s", - string(dumpReq), string(body), string(dumpRes)) + return fmt.Errorf("bad datadog request and response:\n%s\n%s", string(dumpReq), string(dumpRes)) } return nil diff --git a/metrics_reporter.go b/metrics_reporter.go index ba96ac0..2cfe8e0 100644 --- a/metrics_reporter.go +++ b/metrics_reporter.go @@ -54,13 +54,12 @@ func (mr *MetricsReporter) Report() error { return mr.client.PostSeries(mr.Series(), mr.registry) } -// For each metric associated with the current Registry, convert it to a +// For each metric assocaited with the current Registry, convert it to a // `Series` message, and return them all as a single array. The series messages // will have the current hostname of the `Client`. func (mr *MetricsReporter) Series() []Series { now := time.Now().Unix() - - var series []Series + series := make([]Series, 0) mr.registry.Each(func(name string, metric interface{}) { s := mr.series(now, name, metric) series = append(series, s...) From 50ac884e9fc5b7a9eead8a909d842629a60cda90 Mon Sep 17 00:00:00 2001 From: Oliver Bestmann Date: Mon, 17 Sep 2018 07:34:41 +0000 Subject: [PATCH 22/23] Do not log the request body --- client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.go b/client.go index 9d53ec3..bfad8af 100644 --- a/client.go +++ b/client.go @@ -160,7 +160,7 @@ func (c *Client) doRequest(url string, body []byte) (err error) { defer resp.Body.Close() if resp.StatusCode/100 != 2 { - dumpReq, _ := httputil.DumpRequest(req, true) + dumpReq, _ := httputil.DumpRequest(req, false) dumpRes, _ := httputil.DumpResponse(resp, true) return fmt.Errorf("bad datadog request and response:\n%s\n%s", string(dumpReq), string(dumpRes)) } From 49d07c2e2e7bd808fe395fced7936226d1dabc14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=B6hren?= Date: Tue, 18 Sep 2018 10:03:40 +0200 Subject: [PATCH 23/23] Update .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3c898ca..fd41583 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -# Created by .ignore support plugin (hsz.mobi) ### Go template # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o