From 61a55145a197a22835a809c28a42b00588e3f2e9 Mon Sep 17 00:00:00 2001 From: Mike Dame Date: Tue, 7 Feb 2023 23:46:31 +0000 Subject: [PATCH] Use latest metric timestamp for info metrics --- .../googlemanagedprometheus/extra_metrics.go | 75 ++++++++++++++++++- .../extra_metrics_test.go | 46 ++++++++---- 2 files changed, 106 insertions(+), 15 deletions(-) diff --git a/exporter/collector/googlemanagedprometheus/extra_metrics.go b/exporter/collector/googlemanagedprometheus/extra_metrics.go index 397ac7ddf..5e92fb7fb 100644 --- a/exporter/collector/googlemanagedprometheus/extra_metrics.go +++ b/exporter/collector/googlemanagedprometheus/extra_metrics.go @@ -31,13 +31,65 @@ func AddTargetInfoMetric(m pmetric.Metrics) { for i := 0; i < rms.Len(); i++ { rm := rms.At(i) + // Keep track of the most recent time in this resource's metrics + // Use that time for the timestamp of the new metric + latestTime := time.Time{} + for j := 0; j < rm.ScopeMetrics().Len(); j++ { + for k := 0; k < rm.ScopeMetrics().At(j).Metrics().Len(); k++ { + metric := rm.ScopeMetrics().At(j).Metrics().At(k) + + switch metric.Type() { + case pmetric.MetricTypeSum: + sum := metric.Sum() + points := sum.DataPoints() + for x := 0; x < points.Len(); x++ { + if latestTime.Before(points.At(x).Timestamp().AsTime()) { + latestTime = points.At(x).Timestamp().AsTime() + } + } + case pmetric.MetricTypeGauge: + gauge := metric.Gauge() + points := gauge.DataPoints() + for x := 0; x < points.Len(); x++ { + if latestTime.Before(points.At(x).Timestamp().AsTime()) { + latestTime = points.At(x).Timestamp().AsTime() + } + } + case pmetric.MetricTypeSummary: + summary := metric.Summary() + points := summary.DataPoints() + for x := 0; x < points.Len(); x++ { + if latestTime.Before(points.At(x).Timestamp().AsTime()) { + latestTime = points.At(x).Timestamp().AsTime() + } + } + case pmetric.MetricTypeHistogram: + hist := metric.Histogram() + points := hist.DataPoints() + for x := 0; x < points.Len(); x++ { + if latestTime.Before(points.At(x).Timestamp().AsTime()) { + latestTime = points.At(x).Timestamp().AsTime() + } + } + case pmetric.MetricTypeExponentialHistogram: + eh := metric.ExponentialHistogram() + points := eh.DataPoints() + for x := 0; x < points.Len(); x++ { + if latestTime.Before(points.At(x).Timestamp().AsTime()) { + latestTime = points.At(x).Timestamp().AsTime() + } + } + } + } + } + // create the target_info metric as a Gauge with value 1 targetInfoMetric := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() targetInfoMetric.SetName("target_info") dataPoint := targetInfoMetric.SetEmptyGauge().DataPoints().AppendEmpty() dataPoint.SetIntValue(1) - dataPoint.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + dataPoint.SetTimestamp(pcommon.NewTimestampFromTime(latestTime)) // copy Resource attributes to the metric except for attributes which will already be present in the MonitoredResource labels rm.Resource().Attributes().Range(func(k string, v pcommon.Value) bool { @@ -68,12 +120,14 @@ func AddScopeInfoMetric(m pmetric.Metrics) { scopeInfoMetric.SetName("otel_scope_info") dataPoint := scopeInfoMetric.SetEmptyGauge().DataPoints().AppendEmpty() dataPoint.SetIntValue(1) - dataPoint.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) sm.Scope().Attributes().Range(func(k string, v pcommon.Value) bool { dataPoint.Attributes().PutStr(k, v.AsString()) return true }) + // Keep track of the most recent time in this scope's metrics + // Use that time for the timestamp of the new metric + latestTime := time.Time{} for k := 0; k < sm.Metrics().Len(); k++ { metric := sm.Metrics().At(k) switch metric.Type() { @@ -84,6 +138,9 @@ func AddScopeInfoMetric(m pmetric.Metrics) { point := points.At(x) point.Attributes().PutStr("otel_scope_name", sm.Scope().Name()) point.Attributes().PutStr("otel_scope_version", sm.Scope().Version()) + if latestTime.Before(points.At(x).Timestamp().AsTime()) { + latestTime = points.At(x).Timestamp().AsTime() + } } case pmetric.MetricTypeGauge: gauge := metric.Gauge() @@ -92,6 +149,9 @@ func AddScopeInfoMetric(m pmetric.Metrics) { point := points.At(x) point.Attributes().PutStr("otel_scope_name", sm.Scope().Name()) point.Attributes().PutStr("otel_scope_version", sm.Scope().Version()) + if latestTime.Before(points.At(x).Timestamp().AsTime()) { + latestTime = points.At(x).Timestamp().AsTime() + } } case pmetric.MetricTypeSummary: summary := metric.Summary() @@ -100,6 +160,9 @@ func AddScopeInfoMetric(m pmetric.Metrics) { point := points.At(x) point.Attributes().PutStr("otel_scope_name", sm.Scope().Name()) point.Attributes().PutStr("otel_scope_version", sm.Scope().Version()) + if latestTime.Before(points.At(x).Timestamp().AsTime()) { + latestTime = points.At(x).Timestamp().AsTime() + } } case pmetric.MetricTypeHistogram: hist := metric.Histogram() @@ -108,6 +171,9 @@ func AddScopeInfoMetric(m pmetric.Metrics) { point := points.At(x) point.Attributes().PutStr("otel_scope_name", sm.Scope().Name()) point.Attributes().PutStr("otel_scope_version", sm.Scope().Version()) + if latestTime.Before(points.At(x).Timestamp().AsTime()) { + latestTime = points.At(x).Timestamp().AsTime() + } } case pmetric.MetricTypeExponentialHistogram: eh := metric.ExponentialHistogram() @@ -116,9 +182,14 @@ func AddScopeInfoMetric(m pmetric.Metrics) { point := points.At(x) point.Attributes().PutStr("otel_scope_name", sm.Scope().Name()) point.Attributes().PutStr("otel_scope_version", sm.Scope().Version()) + if latestTime.Before(points.At(x).Timestamp().AsTime()) { + latestTime = points.At(x).Timestamp().AsTime() + } } } } + + dataPoint.SetTimestamp(pcommon.NewTimestampFromTime(latestTime)) } } } diff --git a/exporter/collector/googlemanagedprometheus/extra_metrics_test.go b/exporter/collector/googlemanagedprometheus/extra_metrics_test.go index bbf07ccbb..f27aeac5e 100644 --- a/exporter/collector/googlemanagedprometheus/extra_metrics_test.go +++ b/exporter/collector/googlemanagedprometheus/extra_metrics_test.go @@ -16,12 +16,14 @@ package googlemanagedprometheus import ( "testing" + "time" "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" ) -func testMetric() pmetric.Metrics { +func testMetric(timestamp time.Time) pmetric.Metrics { metrics := pmetric.NewMetrics() rm := metrics.ResourceMetrics().AppendEmpty() @@ -38,10 +40,12 @@ func testMetric() pmetric.Metrics { metric := sm.Metrics().AppendEmpty() metric.SetName("baz-metric") metric.SetEmptyGauge().DataPoints().AppendEmpty().SetIntValue(2112) + metric.Gauge().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) return metrics } func TestAddExtraMetrics(t *testing.T) { + timestamp := time.Now() for _, tc := range []struct { testFunc func(pmetric.Metrics) pmetric.ResourceMetricsSlice input pmetric.Metrics @@ -54,9 +58,9 @@ func TestAddExtraMetrics(t *testing.T) { AddTargetInfoMetric(m) return m.ResourceMetrics() }, - input: testMetric(), + input: testMetric(timestamp), expected: func() pmetric.ResourceMetricsSlice { - metrics := testMetric().ResourceMetrics() + metrics := testMetric(timestamp).ResourceMetrics() // Insert a new, empty ScopeMetricsSlice for this resource that will hold target_info sm := metrics.At(0).ScopeMetrics().AppendEmpty() @@ -64,6 +68,7 @@ func TestAddExtraMetrics(t *testing.T) { metric.SetName("target_info") metric.SetEmptyGauge().DataPoints().AppendEmpty().SetIntValue(1) metric.Gauge().DataPoints().At(0).Attributes().PutStr("foo-label", "bar") + metric.Gauge().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) return metrics }(), }, @@ -73,9 +78,9 @@ func TestAddExtraMetrics(t *testing.T) { AddScopeInfoMetric(m) return m.ResourceMetrics() }, - input: testMetric(), + input: testMetric(timestamp), expected: func() pmetric.ResourceMetricsSlice { - metrics := testMetric().ResourceMetrics() + metrics := testMetric(timestamp).ResourceMetrics() // Insert the scope_info metric into the existing ScopeMetricsSlice sm := metrics.At(0).ScopeMetrics().At(0) @@ -88,6 +93,7 @@ func TestAddExtraMetrics(t *testing.T) { metric := sm.Metrics().At(i) metric.Gauge().DataPoints().At(0).Attributes().PutStr("otel_scope_name", "myscope") metric.Gauge().DataPoints().At(0).Attributes().PutStr("otel_scope_version", "v0.0.1") + metric.Gauge().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) } return metrics }(), @@ -99,12 +105,12 @@ func TestAddExtraMetrics(t *testing.T) { return m.ResourceMetrics() }, input: func() pmetric.Metrics { - metrics := testMetric() + metrics := testMetric(timestamp) metrics.ResourceMetrics().At(0).ScopeMetrics().At(0).Scope().Attributes().PutStr("foo_attribute", "bar") return metrics }(), expected: func() pmetric.ResourceMetricsSlice { - metrics := testMetric().ResourceMetrics() + metrics := testMetric(timestamp).ResourceMetrics() metrics.At(0).ScopeMetrics().At(0).Scope().Attributes().PutStr("foo_attribute", "bar") // Insert the scope_info metric into the existing ScopeMetricsSlice @@ -119,6 +125,7 @@ func TestAddExtraMetrics(t *testing.T) { metric := sm.Metrics().At(i) metric.Gauge().DataPoints().At(0).Attributes().PutStr("otel_scope_name", "myscope") metric.Gauge().DataPoints().At(0).Attributes().PutStr("otel_scope_version", "v0.0.1") + scopeInfoMetric.Gauge().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) } return metrics }(), @@ -130,9 +137,9 @@ func TestAddExtraMetrics(t *testing.T) { AddTargetInfoMetric(m) return m.ResourceMetrics() }, - input: testMetric(), + input: testMetric(timestamp), expected: func() pmetric.ResourceMetricsSlice { - metrics := testMetric().ResourceMetrics() + metrics := testMetric(timestamp).ResourceMetrics() scopeMetrics := metrics.At(0).ScopeMetrics() // Insert a new, empty ScopeMetricsSlice for this resource that will hold target_info @@ -141,6 +148,7 @@ func TestAddExtraMetrics(t *testing.T) { metric.SetName("target_info") metric.SetEmptyGauge().DataPoints().AppendEmpty().SetIntValue(1) metric.Gauge().DataPoints().At(0).Attributes().PutStr("foo-label", "bar") + metric.Gauge().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) // Insert the scope_info metric into the existing ScopeMetricsSlice sm = scopeMetrics.At(0) @@ -155,6 +163,7 @@ func TestAddExtraMetrics(t *testing.T) { metric := sm.Metrics().At(i) metric.Gauge().DataPoints().At(0).Attributes().PutStr("otel_scope_name", "myscope") metric.Gauge().DataPoints().At(0).Attributes().PutStr("otel_scope_version", "v0.0.1") + metric.Gauge().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) } return metrics @@ -167,9 +176,9 @@ func TestAddExtraMetrics(t *testing.T) { AddScopeInfoMetric(m) return m.ResourceMetrics() }, - input: testMetric(), + input: testMetric(timestamp), expected: func() pmetric.ResourceMetricsSlice { - metrics := testMetric().ResourceMetrics() + metrics := testMetric(timestamp).ResourceMetrics() scopeMetrics := metrics.At(0).ScopeMetrics() // Insert a new, empty ScopeMetricsSlice for this resource that will hold target_info @@ -178,6 +187,7 @@ func TestAddExtraMetrics(t *testing.T) { metric.SetName("target_info") metric.SetEmptyGauge().DataPoints().AppendEmpty().SetIntValue(1) metric.Gauge().DataPoints().At(0).Attributes().PutStr("foo-label", "bar") + metric.Gauge().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) // Insert the scope_info metric into the existing ScopeMetricsSlice sm = scopeMetrics.At(0) @@ -192,6 +202,7 @@ func TestAddExtraMetrics(t *testing.T) { metric := sm.Metrics().At(i) metric.Gauge().DataPoints().At(0).Attributes().PutStr("otel_scope_name", "myscope") metric.Gauge().DataPoints().At(0).Attributes().PutStr("otel_scope_version", "v0.0.1") + metric.Gauge().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) } return metrics @@ -204,41 +215,49 @@ func TestAddExtraMetrics(t *testing.T) { return m.ResourceMetrics() }, input: func() pmetric.Metrics { - metrics := testMetric() + metrics := testMetric(timestamp) sum := metrics.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().AppendEmpty() sum.SetName("sum-metric") sum.SetEmptySum().DataPoints().AppendEmpty().SetIntValue(1234) + sum.Sum().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) summary := metrics.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().AppendEmpty() summary.SetName("summary-metric") summary.SetEmptySummary().DataPoints().AppendEmpty().SetSum(float64(1.0)) + summary.Summary().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) histogram := metrics.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().AppendEmpty() histogram.SetName("histogram-metric") histogram.SetEmptyHistogram().DataPoints().AppendEmpty().StartTimestamp().AsTime().Year() + histogram.Histogram().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) expHistogram := metrics.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().AppendEmpty() expHistogram.SetName("exponential-histogram") expHistogram.SetEmptyExponentialHistogram().DataPoints().AppendEmpty().StartTimestamp().AsTime().Year() + expHistogram.ExponentialHistogram().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) return metrics }(), expected: func() pmetric.ResourceMetricsSlice { - testMetrics := testMetric() + testMetrics := testMetric(timestamp) sum := testMetrics.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().AppendEmpty() sum.SetName("sum-metric") sum.SetEmptySum().DataPoints().AppendEmpty().SetIntValue(1234) + sum.Sum().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) summary := testMetrics.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().AppendEmpty() summary.SetName("summary-metric") summary.SetEmptySummary().DataPoints().AppendEmpty().SetSum(float64(1.0)) + summary.Summary().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) histogram := testMetrics.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().AppendEmpty() histogram.SetName("histogram-metric") histogram.SetEmptyHistogram().DataPoints().AppendEmpty().StartTimestamp().AsTime().Year() + histogram.Histogram().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) expHistogram := testMetrics.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().AppendEmpty() expHistogram.SetName("exponential-histogram") expHistogram.SetEmptyExponentialHistogram().DataPoints().AppendEmpty().StartTimestamp().AsTime().Year() + expHistogram.ExponentialHistogram().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) metrics := testMetrics.ResourceMetrics() // Insert the scope_info metric into the existing ScopeMetricsSlice @@ -246,6 +265,7 @@ func TestAddExtraMetrics(t *testing.T) { scopeInfoMetric := sm.Metrics().AppendEmpty() scopeInfoMetric.SetName("otel_scope_info") scopeInfoMetric.SetEmptyGauge().DataPoints().AppendEmpty().SetIntValue(1) + scopeInfoMetric.Gauge().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) // add otel_scope_* attributes to all metrics in this scope (including otel_scope_info) for i := 0; i < sm.Metrics().Len(); i++ {