Skip to content

Commit

Permalink
feat(outputs.datadog): Add support for submitting alongside dd-agent
Browse files Browse the repository at this point in the history
  • Loading branch information
jdheyburn committed Aug 5, 2024
1 parent 094eff6 commit 7051a9c
Show file tree
Hide file tree
Showing 4 changed files with 378 additions and 17 deletions.
16 changes: 11 additions & 5 deletions plugins/outputs/datadog/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
## Override the default (none) compression used to send data.
## Supports: "zlib", "none"
# compression = "none"

## Convert counts to rates
## Use this to be able to submit metrics from telegraf alongside Datadog agent
# should_rate_counts = true

## When should_rate_counts is enabled, this overrides the
## default (10s) rate interval used to divide count metrics by
# rate_interval = 20
```

## Metrics
Expand All @@ -46,11 +54,9 @@ field key with a `.` character.
Field values are converted to floating point numbers. Strings and floats that
cannot be sent over JSON, namely NaN and Inf, are ignored.

We do not send `Rate` types. Counts are sent as `count`, with an
interval hard-coded to 1. Note that this behavior does *not* play
super-well if running simultaneously with current Datadog agents; they
will attempt to change to `Rate` with `interval=10`. We prefer this
method, however, as it reflects the raw data more accurately.
Enabling the `should_rate_counts` will convert `count` metrics to `rate`
and divide it by the `rate_interval`. This will allow telegraf to run
alongside current Datadog agents.

[metrics]: https://docs.datadoghq.com/api/v1/metrics/#submit-metrics
[apikey]: https://app.datadoghq.com/account/settings#api
57 changes: 45 additions & 12 deletions plugins/outputs/datadog/datadog.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ import (
var sampleConfig string

type Datadog struct {
Apikey string `toml:"apikey"`
Timeout config.Duration `toml:"timeout"`
URL string `toml:"url"`
Compression string `toml:"compression"`
Log telegraf.Logger `toml:"-"`
Apikey string `toml:"apikey"`
Timeout config.Duration `toml:"timeout"`
URL string `toml:"url"`
Compression string `toml:"compression"`
ShouldRateCounts bool `toml:"should_rate_counts"`
RateInterval int64 `toml:"rate_interval"`
Log telegraf.Logger `toml:"-"`

client *http.Client
proxy.HTTPProxy
Expand Down Expand Up @@ -75,15 +77,15 @@ func (d *Datadog) Connect() error {
return nil
}

func (d *Datadog) Write(metrics []telegraf.Metric) error {
ts := TimeSeries{}
func (d *Datadog) convertToDatadogMetric(metrics []telegraf.Metric) ([]*Metric, int) {
tempSeries := []*Metric{}
metricCounter := 0

for _, m := range metrics {
if dogMs, err := buildMetrics(m); err == nil {
metricTags := buildTags(m.TagList())
host, _ := m.GetTag("host")
metricType, _ := m.GetTag("metric_type")

if len(dogMs) == 0 {
continue
Expand All @@ -99,9 +101,19 @@ func (d *Datadog) Write(metrics []telegraf.Metric) error {
dname = m.Name() + "." + fieldName
}
var tname string
var interval int64
interval = 1
switch m.Type() {
case telegraf.Counter:
tname = "count"
case telegraf.Counter, telegraf.Untyped:
if d.ShouldRateCounts && isRateable(metricType, fieldName) {
interval = d.RateInterval
dogM[1] = dogM[1] / float64(interval)
tname = "rate"
} else if m.Type() == telegraf.Counter {
tname = "count"
} else {
tname = ""
}
case telegraf.Gauge:
tname = "gauge"
default:
Expand All @@ -112,7 +124,7 @@ func (d *Datadog) Write(metrics []telegraf.Metric) error {
Tags: metricTags,
Host: host,
Type: tname,
Interval: 1,
Interval: interval,
}
metric.Points[0] = dogM
tempSeries = append(tempSeries, metric)
Expand All @@ -122,6 +134,12 @@ func (d *Datadog) Write(metrics []telegraf.Metric) error {
d.Log.Infof("Unable to build Metric for %s due to error '%v', skipping", m.Name(), err)
}
}
return tempSeries, metricCounter
}

func (d *Datadog) Write(metrics []telegraf.Metric) error {
ts := TimeSeries{}
tempSeries, metricCounter := d.convertToDatadogMetric(metrics)

if len(tempSeries) == 0 {
return nil
Expand Down Expand Up @@ -220,6 +238,20 @@ func verifyValue(v interface{}) bool {
return true
}

func isRateable(metricType string, fieldName string) bool {
switch metricType {
case
"counter":
return true
case
"timing",
"histogram":
return fieldName == "count"
default:
return false
}
}

func (p *Point) setValue(v interface{}) error {
switch d := v.(type) {
case int64:
Expand All @@ -246,8 +278,9 @@ func (d *Datadog) Close() error {
func init() {
outputs.Add("datadog", func() telegraf.Output {
return &Datadog{
URL: datadogAPI,
Compression: "none",
URL: datadogAPI,
Compression: "none",
RateInterval: 10,
}
})
}
Loading

0 comments on commit 7051a9c

Please sign in to comment.