Skip to content

Commit

Permalink
[exporter/datadogexporter] Export delta sums as counts (open-telemetr…
Browse files Browse the repository at this point in the history
…y#4609)

Exports OTLP delta sums (both monotonic and non-monotonic) as Datadog counts with no interval set. Commits can be reviewed separately.

**Is this a breaking change?** Yes.

**Link to tracking Issue:** n/a.

**Testing:** Updated unit tests.
  • Loading branch information
mx-psi authored Aug 13, 2021
1 parent 6ca7e97 commit 61a6b5a
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 31 deletions.
24 changes: 15 additions & 9 deletions exporter/datadogexporter/internal/metrics/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ import (
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/config"
)

type MetricDataType string

const (
// Gauge is the Datadog Gauge metric type
Gauge string = "gauge"
Gauge MetricDataType = "gauge"
// Count is the Datadog Count metric type
Count string = "count"
otelNamespacePrefix string = "otel"
Count MetricDataType = "count"
otelNamespacePrefix string = "otel"
)

// newMetric creates a new Datadog metric given a name, a Unix nanoseconds timestamp
Expand All @@ -47,20 +49,24 @@ func newMetric(name string, ts uint64, value float64, tags []string) datadog.Met
return metric
}

// NewMetric creates a new Datadog metric given a name, a type, a Unix nanoseconds timestamp
// a value and a slice of tags
func NewMetric(name string, dt MetricDataType, ts uint64, value float64, tags []string) datadog.Metric {
metric := newMetric(name, ts, value, tags)
metric.SetType(string(dt))
return metric
}

// NewGauge creates a new Datadog Gauge metric given a name, a Unix nanoseconds timestamp
// a value and a slice of tags
func NewGauge(name string, ts uint64, value float64, tags []string) datadog.Metric {
gauge := newMetric(name, ts, value, tags)
gauge.SetType(Gauge)
return gauge
return NewMetric(name, Gauge, ts, value, tags)
}

// NewCount creates a new Datadog count metric given a name, a Unix nanoseconds timestamp
// a value and a slice of tags
func NewCount(name string, ts uint64, value float64, tags []string) datadog.Metric {
count := newMetric(name, ts, value, tags)
count.SetType(Count)
return count
return NewMetric(name, Count, ts, value, tags)
}

// DefaultMetrics creates built-in metrics to report that an exporter is running
Expand Down
4 changes: 2 additions & 2 deletions exporter/datadogexporter/internal/metrics/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ func TestNewType(t *testing.T) {
tags := []string{"tag:value"}

gauge := NewGauge(name, ts, value, tags)
assert.Equal(t, gauge.GetType(), Gauge)
assert.Equal(t, gauge.GetType(), string(Gauge))

count := NewCount(name, ts, value, tags)
assert.Equal(t, count.GetType(), Count)
assert.Equal(t, count.GetType(), string(Count))

}

Expand Down
10 changes: 5 additions & 5 deletions exporter/datadogexporter/metrics_translator.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func metricDimensionsToMapKey(name string, tags []string) string {
}

// mapNumberMetrics maps double datapoints into Datadog metrics
func mapNumberMetrics(name string, slice pdata.NumberDataPointSlice, attrTags []string) []datadog.Metric {
func mapNumberMetrics(name string, dt metrics.MetricDataType, slice pdata.NumberDataPointSlice, attrTags []string) []datadog.Metric {
ms := make([]datadog.Metric, 0, slice.Len())
for i := 0; i < slice.Len(); i++ {
p := slice.At(i)
Expand All @@ -82,7 +82,7 @@ func mapNumberMetrics(name string, slice pdata.NumberDataPointSlice, attrTags []
val = float64(p.IntVal())
}
ms = append(ms,
metrics.NewGauge(name, uint64(p.Timestamp()), val, tags),
metrics.NewMetric(name, dt, uint64(p.Timestamp()), val, tags),
)
}
return ms
Expand Down Expand Up @@ -257,17 +257,17 @@ func mapMetrics(logger *zap.Logger, cfg config.MetricsConfig, prevPts *ttlmap.TT
var datapoints []datadog.Metric
switch md.DataType() {
case pdata.MetricDataTypeGauge:
datapoints = mapNumberMetrics(md.Name(), md.Gauge().DataPoints(), attributeTags)
datapoints = mapNumberMetrics(md.Name(), metrics.Gauge, md.Gauge().DataPoints(), attributeTags)
case pdata.MetricDataTypeSum:
switch md.Sum().AggregationTemporality() {
case pdata.AggregationTemporalityCumulative:
if cfg.SendMonotonic && isCumulativeMonotonic(md) {
datapoints = mapNumberMonotonicMetrics(md.Name(), prevPts, md.Sum().DataPoints(), attributeTags)
} else {
datapoints = mapNumberMetrics(md.Name(), md.Sum().DataPoints(), attributeTags)
datapoints = mapNumberMetrics(md.Name(), metrics.Gauge, md.Sum().DataPoints(), attributeTags)
}
case pdata.AggregationTemporalityDelta:
datapoints = mapNumberMetrics(md.Name(), md.Sum().DataPoints(), attributeTags)
datapoints = mapNumberMetrics(md.Name(), metrics.Count, md.Sum().DataPoints(), attributeTags)
default: // pdata.AggregationTemporalityUnspecified or any other not supported type
logger.Debug("Unknown or unsupported aggregation temporality",
zap.String("metric name", md.Name()),
Expand Down
86 changes: 71 additions & 15 deletions exporter/datadogexporter/metrics_translator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func TestMetricValue(t *testing.T) {
)

metric := metrics.NewGauge(name, ts, value, tags)
assert.Equal(t, metrics.Gauge, metric.GetType())
assert.Equal(t, string(metrics.Gauge), metric.GetType())
assert.Equal(t, tags, metric.Tags)
}

Expand Down Expand Up @@ -133,13 +133,18 @@ func TestMapIntMetrics(t *testing.T) {
point.SetTimestamp(ts)

assert.ElementsMatch(t,
mapNumberMetrics("int64.test", slice, []string{}),
mapNumberMetrics("int64.test", metrics.Gauge, slice, []string{}),
[]datadog.Metric{metrics.NewGauge("int64.test", uint64(ts), 17, []string{})},
)

assert.ElementsMatch(t,
mapNumberMetrics("int64.delta.test", metrics.Count, slice, []string{}),
[]datadog.Metric{metrics.NewCount("int64.delta.test", uint64(ts), 17, []string{})},
)

// With attribute tags
assert.ElementsMatch(t,
mapNumberMetrics("int64.test", slice, []string{"attribute_tag:attribute_value"}),
mapNumberMetrics("int64.test", metrics.Gauge, slice, []string{"attribute_tag:attribute_value"}),
[]datadog.Metric{metrics.NewGauge("int64.test", uint64(ts), 17, []string{"attribute_tag:attribute_value"})},
)
}
Expand All @@ -152,13 +157,18 @@ func TestMapDoubleMetrics(t *testing.T) {
point.SetTimestamp(ts)

assert.ElementsMatch(t,
mapNumberMetrics("float64.test", slice, []string{}),
mapNumberMetrics("float64.test", metrics.Gauge, slice, []string{}),
[]datadog.Metric{metrics.NewGauge("float64.test", uint64(ts), math.Pi, []string{})},
)

assert.ElementsMatch(t,
mapNumberMetrics("float64.delta.test", metrics.Count, slice, []string{}),
[]datadog.Metric{metrics.NewCount("float64.delta.test", uint64(ts), math.Pi, []string{})},
)

// With attribute tags
assert.ElementsMatch(t,
mapNumberMetrics("float64.test", slice, []string{"attribute_tag:attribute_value"}),
mapNumberMetrics("float64.test", metrics.Gauge, slice, []string{"attribute_tag:attribute_value"}),
[]datadog.Metric{metrics.NewGauge("float64.test", uint64(ts), math.Pi, []string{"attribute_tag:attribute_value"})},
)
}
Expand Down Expand Up @@ -640,7 +650,7 @@ func createTestMetrics() pdata.Metrics {

// Int Sum (delta)
met = metricsArray.AppendEmpty()
met.SetName("int.sum")
met.SetName("int.delta.sum")
met.SetDataType(pdata.MetricDataTypeSum)
met.Sum().SetAggregationTemporality(pdata.AggregationTemporalityDelta)
dpsInt = met.Sum().DataPoints()
Expand All @@ -650,7 +660,27 @@ func createTestMetrics() pdata.Metrics {

// Double Sum (delta)
met = metricsArray.AppendEmpty()
met.SetName("double.sum")
met.SetName("double.delta.sum")
met.SetDataType(pdata.MetricDataTypeSum)
met.Sum().SetAggregationTemporality(pdata.AggregationTemporalityDelta)
dpsDouble = met.Sum().DataPoints()
dpDouble = dpsDouble.AppendEmpty()
dpDouble.SetTimestamp(seconds(0))
dpDouble.SetDoubleVal(math.E)

// Int Sum (delta monotonic)
met = metricsArray.AppendEmpty()
met.SetName("int.delta.monotonic.sum")
met.SetDataType(pdata.MetricDataTypeSum)
met.Sum().SetAggregationTemporality(pdata.AggregationTemporalityDelta)
dpsInt = met.Sum().DataPoints()
dpInt = dpsInt.AppendEmpty()
dpInt.SetTimestamp(seconds(0))
dpInt.SetIntVal(2)

// Double Sum (delta monotonic)
met = metricsArray.AppendEmpty()
met.SetName("double.delta.monotonic.sum")
met.SetDataType(pdata.MetricDataTypeSum)
met.Sum().SetAggregationTemporality(pdata.AggregationTemporalityDelta)
dpsDouble = met.Sum().DataPoints()
Expand All @@ -674,6 +704,28 @@ func createTestMetrics() pdata.Metrics {
met.SetName("int.cumulative.sum")
met.SetDataType(pdata.MetricDataTypeSum)
met.Sum().SetAggregationTemporality(pdata.AggregationTemporalityCumulative)
dpsInt = met.Sum().DataPoints()
dpsInt.EnsureCapacity(2)
dpInt = dpsInt.AppendEmpty()
dpInt.SetTimestamp(seconds(0))
dpInt.SetIntVal(4)

// Double Sum (cumulative)
met = metricsArray.AppendEmpty()
met.SetName("double.cumulative.sum")
met.SetDataType(pdata.MetricDataTypeSum)
met.Sum().SetAggregationTemporality(pdata.AggregationTemporalityCumulative)
dpsDouble = met.Sum().DataPoints()
dpsDouble.EnsureCapacity(2)
dpDouble = dpsDouble.AppendEmpty()
dpDouble.SetTimestamp(seconds(0))
dpDouble.SetDoubleVal(4)

// Int Sum (cumulative monotonic)
met = metricsArray.AppendEmpty()
met.SetName("int.cumulative.monotonic.sum")
met.SetDataType(pdata.MetricDataTypeSum)
met.Sum().SetAggregationTemporality(pdata.AggregationTemporalityCumulative)
met.Sum().SetIsMonotonic(true)
dpsInt = met.Sum().DataPoints()
dpsInt.EnsureCapacity(2)
Expand All @@ -684,9 +736,9 @@ func createTestMetrics() pdata.Metrics {
dpInt.SetTimestamp(seconds(2))
dpInt.SetIntVal(7)

// Double Sum (cumulative)
// Double Sum (cumulative monotonic)
met = metricsArray.AppendEmpty()
met.SetName("double.cumulative.sum")
met.SetName("double.cumulative.monotonic.sum")
met.SetDataType(pdata.MetricDataTypeSum)
met.Sum().SetAggregationTemporality(pdata.AggregationTemporalityCumulative)
met.Sum().SetIsMonotonic(true)
Expand Down Expand Up @@ -724,8 +776,8 @@ func testGauge(name string, val float64) datadog.Metric {
return m
}

func testCount(name string, val float64) datadog.Metric {
m := metrics.NewCount(name, 2*1e9, val, []string{})
func testCount(name string, val float64, seconds uint64) datadog.Metric {
m := metrics.NewCount(name, seconds*1e9, val, []string{})
m.SetHost(testHostname)
return m
}
Expand All @@ -746,14 +798,18 @@ func TestMapMetrics(t *testing.T) {
assert.ElementsMatch(t, filtered, []datadog.Metric{
testGauge("int.gauge", 1),
testGauge("double.gauge", math.Pi),
testGauge("int.sum", 2),
testGauge("double.sum", math.E),
testCount("int.delta.sum", 2, 0),
testCount("double.delta.sum", math.E, 0),
testCount("int.delta.monotonic.sum", 2, 0),
testCount("double.delta.monotonic.sum", math.E, 0),
testGauge("double.histogram.sum", math.Phi),
testGauge("double.histogram.count", 20),
testGauge("summary.sum", 10_000),
testGauge("summary.count", 100),
testCount("int.cumulative.sum", 3),
testCount("double.cumulative.sum", math.Pi),
testGauge("int.cumulative.sum", 4),
testGauge("double.cumulative.sum", 4),
testCount("int.cumulative.monotonic.sum", 3, 2),
testCount("double.cumulative.monotonic.sum", math.Pi, 2),
})

// One metric type was unknown or unsupported
Expand Down

0 comments on commit 61a6b5a

Please sign in to comment.