From 9e2210e1cd78439b517a98e13a6cb774d22a8062 Mon Sep 17 00:00:00 2001 From: Gabriel Aszalos Date: Mon, 22 May 2023 16:27:38 +0300 Subject: [PATCH] exporter/datadogexporter: add containers.* metrics mapping (#22150) * exporter/datadogexporter: add containers.* metrics mapping * Update exporter/datadogexporter/internal/metrics/system.go Co-authored-by: Pablo Baeyens * Update exporter/datadogexporter/internal/metrics/system_deprecated.go Co-authored-by: Pablo Baeyens --------- Co-authored-by: Pablo Baeyens --- .chloggen/gbbr_container-metrics.yaml | 16 +++++ .../internal/metrics/system.go | 71 +++++++++++++++++++ .../internal/metrics/system_deprecated.go | 70 ++++++++++++++++++ exporter/datadogexporter/metrics_exporter.go | 2 + 4 files changed, 159 insertions(+) create mode 100755 .chloggen/gbbr_container-metrics.yaml diff --git a/.chloggen/gbbr_container-metrics.yaml b/.chloggen/gbbr_container-metrics.yaml new file mode 100755 index 0000000000000..da60df18c4c88 --- /dev/null +++ b/.chloggen/gbbr_container-metrics.yaml @@ -0,0 +1,16 @@ +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: exporter/datadog + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Map Docker stats receiver metrics to Datadog container metrics. + +# One or more tracking issues related to the change +issues: [22149] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: This change enables the use of the Containers (Overview) dashboard. diff --git a/exporter/datadogexporter/internal/metrics/system.go b/exporter/datadogexporter/internal/metrics/system.go index 13ed2b454af6a..f36c0f7768983 100644 --- a/exporter/datadogexporter/internal/metrics/system.go +++ b/exporter/datadogexporter/internal/metrics/system.go @@ -24,6 +24,11 @@ const ( // Warning: this is not a deep copy. Only some fields are fully copied, others remain shared. This is intentional. // Do not alter the returned metric (or the source one) after copying. func copySystemMetric(src datadogV2.MetricSeries, name string, div float64) datadogV2.MetricSeries { + return copySystemMetricWithUnit(src, name, div, "") +} + +// copySystemMetricWithUnit is equivalent to copySystemMetric, but allows changing the unit. +func copySystemMetricWithUnit(src datadogV2.MetricSeries, name string, div float64, unit string) datadogV2.MetricSeries { cp := src cp.Metric = name // No need to set cp.Interval if cp.Type is gauge. @@ -32,6 +37,9 @@ func copySystemMetric(src datadogV2.MetricSeries, name string, div float64) data // division by 0 or 1 should not have an impact return cp } + if unit != "" { + cp.Unit = &unit + } cp.Points = make([]datadogV2.MetricPoint, len(src.Points)) for i, dp := range src.Points { cp.Points[i].Timestamp = dp.Timestamp @@ -119,3 +127,66 @@ func PrepareSystemMetrics(ms []datadogV2.MetricSeries) []datadogV2.MetricSeries } return series } + +// PrepareContainerMetrics converts OTEL container.* metrics to Datadog container +// metrics. +func PrepareContainerMetrics(ms []datadogV2.MetricSeries) []datadogV2.MetricSeries { + series := ms + for _, m := range ms { + if !strings.HasPrefix(m.Metric, "container.") { + // not what we're looking for + continue + } + switch m.Metric { + case "container.cpu.usage.total": + series = append(series, copySystemMetricWithUnit(m, "container.cpu.usage", 1, "nanocore")) + case "container.cpu.usage.usermode": + series = append(series, copySystemMetricWithUnit(m, "container.cpu.user", 1, "nanocore")) + case "container.cpu.usage.system": + series = append(series, copySystemMetricWithUnit(m, "container.cpu.system", 1, "nanocore")) + case "container.cpu.throttling_data.throttled_time": + series = append(series, copySystemMetric(m, "container.cpu.throttled", 1)) + case "container.cpu.throttling_data.throttled_periods": + series = append(series, copySystemMetric(m, "container.cpu.throttled.periods", 1)) + case "container.memory.usage.total": + series = append(series, copySystemMetric(m, "container.memory.usage", 1)) + case "container.memory.active_anon": + series = append(series, copySystemMetric(m, "container.memory.kernel", 1)) + case "container.memory.hierarchical_memory_limit": + series = append(series, copySystemMetric(m, "container.memory.limit", 1)) + case "container.memory.usage.limit": + series = append(series, copySystemMetric(m, "container.memory.soft_limit", 1)) + case "container.memory.total_cache": + series = append(series, copySystemMetric(m, "container.memory.cache", 1)) + case "container.memory.total_swap": + series = append(series, copySystemMetric(m, "container.memory.swap", 1)) + case "container.blockio.io_service_bytes_recursive": + for _, tag := range m.Tags { + switch tag { + case "operation:write": + series = append(series, copySystemMetric(m, "container.io.write", 1)) + case "operation:read": + series = append(series, copySystemMetric(m, "container.io.read", 1)) + } + } + case "container.blockio.io_serviced_recursive": + for _, tag := range m.Tags { + switch tag { + case "operation:write": + series = append(series, copySystemMetric(m, "container.io.write.operations", 1)) + case "operation:read": + series = append(series, copySystemMetric(m, "container.io.read.operations", 1)) + } + } + case "container.network.io.usage.tx_bytes": + series = append(series, copySystemMetric(m, "container.net.sent", 1)) + case "container.network.io.usage.tx_packets": + series = append(series, copySystemMetric(m, "container.net.sent.packets", 1)) + case "container.network.io.usage.rx_bytes": + series = append(series, copySystemMetric(m, "container.net.rcvd", 1)) + case "container.network.io.usage.rx_packets": + series = append(series, copySystemMetric(m, "container.net.rcvd.packets", 1)) + } + } + return series +} diff --git a/exporter/datadogexporter/internal/metrics/system_deprecated.go b/exporter/datadogexporter/internal/metrics/system_deprecated.go index 4128d1c3d1455..4bc3bd9dfc51c 100644 --- a/exporter/datadogexporter/internal/metrics/system_deprecated.go +++ b/exporter/datadogexporter/internal/metrics/system_deprecated.go @@ -15,6 +15,10 @@ import ( // Warning: this is not a deep copy. Only some fields are fully copied, others remain shared. This is intentional. // Do not alter the returned metric (or the source one) after copying. func copyZorkianSystemMetric(src zorkian.Metric, name string, div float64) zorkian.Metric { + return copyZorkianSystemMetricWithUnit(src, name, div, "") +} + +func copyZorkianSystemMetricWithUnit(src zorkian.Metric, name string, div float64, unit string) zorkian.Metric { cp := src cp.Metric = &name i := 1 @@ -25,6 +29,9 @@ func copyZorkianSystemMetric(src zorkian.Metric, name string, div float64) zorki // division by 0 or 1 should not have an impact return cp } + if unit != "" { + cp.Unit = &unit + } cp.Points = make([]zorkian.DataPoint, len(src.Points)) for i, dp := range src.Points { cp.Points[i][0] = dp[0] @@ -112,3 +119,66 @@ func PrepareZorkianSystemMetrics(ms []zorkian.Metric) []zorkian.Metric { } return series } + +// PrepareZorkianContainerMetrics converts OTEL container.* metrics to Datadog container +// metrics. +func PrepareZorkianContainerMetrics(ms []zorkian.Metric) []zorkian.Metric { + series := ms + for _, m := range ms { + if !strings.HasPrefix(*m.Metric, "container.") { + // not what we're looking for + continue + } + switch *m.Metric { + case "container.cpu.usage.total": + series = append(series, copyZorkianSystemMetricWithUnit(m, "container.cpu.usage", 1, "nanocore")) + case "container.cpu.usage.usermode": + series = append(series, copyZorkianSystemMetricWithUnit(m, "container.cpu.user", 1, "nanocore")) + case "container.cpu.usage.system": + series = append(series, copyZorkianSystemMetricWithUnit(m, "container.cpu.system", 1, "nanocore")) + case "container.cpu.throttling_data.throttled_time": + series = append(series, copyZorkianSystemMetric(m, "container.cpu.throttled", 1)) + case "container.cpu.throttling_data.throttled_periods": + series = append(series, copyZorkianSystemMetric(m, "container.cpu.throttled.periods", 1)) + case "container.memory.usage.total": + series = append(series, copyZorkianSystemMetric(m, "container.memory.usage", 1)) + case "container.memory.active_anon": + series = append(series, copyZorkianSystemMetric(m, "container.memory.kernel", 1)) + case "container.memory.hierarchical_memory_limit": + series = append(series, copyZorkianSystemMetric(m, "container.memory.limit", 1)) + case "container.memory.usage.limit": + series = append(series, copyZorkianSystemMetric(m, "container.memory.soft_limit", 1)) + case "container.memory.total_cache": + series = append(series, copyZorkianSystemMetric(m, "container.memory.cache", 1)) + case "container.memory.total_swap": + series = append(series, copyZorkianSystemMetric(m, "container.memory.swap", 1)) + case "container.blockio.io_service_bytes_recursive": + for _, tag := range m.Tags { + switch tag { + case "operation:write": + series = append(series, copyZorkianSystemMetric(m, "container.io.write", 1)) + case "operation:read": + series = append(series, copyZorkianSystemMetric(m, "container.io.read", 1)) + } + } + case "container.blockio.io_serviced_recursive": + for _, tag := range m.Tags { + switch tag { + case "operation:write": + series = append(series, copyZorkianSystemMetric(m, "container.io.write.operations", 1)) + case "operation:read": + series = append(series, copyZorkianSystemMetric(m, "container.io.read.operations", 1)) + } + } + case "container.network.io.usage.tx_bytes": + series = append(series, copyZorkianSystemMetric(m, "container.net.sent", 1)) + case "container.network.io.usage.tx_packets": + series = append(series, copyZorkianSystemMetric(m, "container.net.sent.packets", 1)) + case "container.network.io.usage.rx_bytes": + series = append(series, copyZorkianSystemMetric(m, "container.net.rcvd", 1)) + case "container.network.io.usage.rx_packets": + series = append(series, copyZorkianSystemMetric(m, "container.net.rcvd.packets", 1)) + } + } + return series +} diff --git a/exporter/datadogexporter/metrics_exporter.go b/exporter/datadogexporter/metrics_exporter.go index 497810a04f2f2..c2c9776660a6a 100644 --- a/exporter/datadogexporter/metrics_exporter.go +++ b/exporter/datadogexporter/metrics_exporter.go @@ -205,6 +205,7 @@ func (exp *metricsExporter) PushMetricsData(ctx context.Context, md pmetric.Metr var ms []datadogV2.MetricSeries ms, sl, sp = consumer.(*metrics.Consumer).All(exp.getPushTime(), exp.params.BuildInfo, tags) ms = metrics.PrepareSystemMetrics(ms) + ms = metrics.PrepareContainerMetrics(ms) err = nil if len(ms) > 0 { @@ -220,6 +221,7 @@ func (exp *metricsExporter) PushMetricsData(ctx context.Context, md pmetric.Metr var ms []zorkian.Metric ms, sl, sp = consumer.(*metrics.ZorkianConsumer).All(exp.getPushTime(), exp.params.BuildInfo, tags) ms = metrics.PrepareZorkianSystemMetrics(ms) + ms = metrics.PrepareZorkianContainerMetrics(ms) err = nil if len(ms) > 0 {