Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add feature gate to convert int metrics to double #844

Merged
merged 2 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 42 additions & 0 deletions exporter/collector/googlemanagedprometheus/extra_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,59 @@ import (
"time"

"github.com/prometheus/common/model"
"go.opentelemetry.io/collector/featuregate"
"go.opentelemetry.io/collector/pdata/pcommon"
"go.opentelemetry.io/collector/pdata/pmetric"
semconv "go.opentelemetry.io/collector/semconv/v1.18.0"
)

var intToDoubleFeatureGate = featuregate.GlobalRegistry().MustRegister(
"exporter.googlemanagedpromethues.intToDouble",
featuregate.StageAlpha,
featuregate.WithRegisterFromVersion("v0.100.0"),
featuregate.WithRegisterDescription("Convert all int metrics to double metrics to avoid incompatible value types."),
featuregate.WithRegisterReferenceURL("https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/issues/798"))

const prometheusMetricMetadataTypeKey = "prometheus.type"

func (c Config) ExtraMetrics(m pmetric.Metrics) {
addUntypedMetrics(m)
c.addTargetInfoMetric(m)
c.addScopeInfoMetric(m)
convertIntToDouble(m)
}

// convertIntToDouble converts all counter and gauge int values to double.
func convertIntToDouble(m pmetric.Metrics) {
if !intToDoubleFeatureGate.IsEnabled() {
return
}
rms := m.ResourceMetrics()
for i := 0; i < rms.Len(); i++ {
rm := rms.At(i)
for j := 0; j < rm.ScopeMetrics().Len(); j++ {
sm := rm.ScopeMetrics().At(j)
for k := 0; k < sm.Metrics().Len(); k++ {
metric := sm.Metrics().At(k)

var points pmetric.NumberDataPointSlice
switch metric.Type() {
case pmetric.MetricTypeSum:
points = metric.Sum().DataPoints()
case pmetric.MetricTypeGauge:
points = metric.Gauge().DataPoints()
default:
continue
}
for x := 0; x < points.Len(); x++ {
point := points.At(x)
if point.ValueType() == pmetric.NumberDataPointValueTypeInt {
point.SetDoubleValue(float64(point.IntValue()))
}
}
}
}
}
}

// addUntypedMetrics looks for any Gauge data point with the special Ops Agent untyped metric
Expand Down
174 changes: 152 additions & 22 deletions exporter/collector/googlemanagedprometheus/extra_metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/featuregate"
"go.opentelemetry.io/collector/pdata/pcommon"
"go.opentelemetry.io/collector/pdata/pmetric"
semconv "go.opentelemetry.io/collector/semconv/v1.18.0"
Expand All @@ -43,19 +45,28 @@ func appendMetric(metrics pmetric.Metrics, timestamp time.Time) pmetric.Metrics

// other metrics should not be copied to target_info
metric := sm.Metrics().AppendEmpty()
metric.SetName("baz-metric")
metric.SetName("gauge-metric")
metric.SetEmptyGauge().DataPoints().AppendEmpty().SetIntValue(2112)
metric.Gauge().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp))
metric = sm.Metrics().AppendEmpty()
metric.SetName("sum-metric")
metric.SetEmptySum().DataPoints().AppendEmpty().SetIntValue(2112)
metric.Sum().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp))
metric = sm.Metrics().AppendEmpty()
metric.SetName("summary-metric")
metric.SetEmptySummary().DataPoints().AppendEmpty().SetCount(2112)
metric.Summary().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp))
return metrics
}

func TestAddExtraMetrics(t *testing.T) {
timestamp := time.Now()
for _, tc := range []struct {
input pmetric.Metrics
expected pmetric.ResourceMetricsSlice
name string
config Config
input pmetric.Metrics
expected pmetric.ResourceMetricsSlice
name string
config Config
enableDoubleFeatureGate bool
}{
{
name: "add target info from resource metric",
Expand Down Expand Up @@ -114,9 +125,20 @@ func TestAddExtraMetrics(t *testing.T) {
// add otel_scope_* attributes to all metrics in this scope (including otel_scope_info)
for i := 0; i < sm.Metrics().Len(); i++ {
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))
switch metric.Type() {
case pmetric.MetricTypeGauge:
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))
case pmetric.MetricTypeSum:
metric.Sum().DataPoints().At(0).Attributes().PutStr("otel_scope_name", "myscope")
metric.Sum().DataPoints().At(0).Attributes().PutStr("otel_scope_version", "v0.0.1")
metric.Sum().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp))
case pmetric.MetricTypeSummary:
metric.Summary().DataPoints().At(0).Attributes().PutStr("otel_scope_name", "myscope")
metric.Summary().DataPoints().At(0).Attributes().PutStr("otel_scope_version", "v0.0.1")
metric.Summary().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp))
}
}
return metrics
}(),
Expand All @@ -143,9 +165,20 @@ func TestAddExtraMetrics(t *testing.T) {
// add otel_scope_* attributes to all metrics in this scope (including otel_scope_info)
for i := 0; i < sm.Metrics().Len(); i++ {
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))
switch metric.Type() {
case pmetric.MetricTypeGauge:
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))
case pmetric.MetricTypeSum:
metric.Sum().DataPoints().At(0).Attributes().PutStr("otel_scope_name", "myscope")
metric.Sum().DataPoints().At(0).Attributes().PutStr("otel_scope_version", "v0.0.1")
metric.Sum().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp))
case pmetric.MetricTypeSummary:
metric.Summary().DataPoints().At(0).Attributes().PutStr("otel_scope_name", "myscope")
metric.Summary().DataPoints().At(0).Attributes().PutStr("otel_scope_version", "v0.0.1")
metric.Summary().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp))
}
}
return metrics
}(),
Expand Down Expand Up @@ -185,18 +218,36 @@ func TestAddExtraMetrics(t *testing.T) {
// add otel_scope_* attributes to all metrics in this scope (including otel_scope_info)
for i := 0; i < sm.Metrics().Len(); i++ {
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))
switch metric.Type() {
case pmetric.MetricTypeGauge:
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))
case pmetric.MetricTypeSum:
metric.Sum().DataPoints().At(0).Attributes().PutStr("otel_scope_name", "myscope")
metric.Sum().DataPoints().At(0).Attributes().PutStr("otel_scope_version", "v0.0.1")
case pmetric.MetricTypeSummary:
metric.Summary().DataPoints().At(0).Attributes().PutStr("otel_scope_name", "myscope")
metric.Summary().DataPoints().At(0).Attributes().PutStr("otel_scope_version", "v0.0.1")
}
}

// add otel_scope_* attributes to all metrics in the second scope
sm = metrics.At(1).ScopeMetrics().At(0)
for i := 0; i < sm.Metrics().Len(); i++ {
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))
switch metric.Type() {
case pmetric.MetricTypeGauge:
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))
case pmetric.MetricTypeSum:
metric.Sum().DataPoints().At(0).Attributes().PutStr("otel_scope_name", "myscope")
metric.Sum().DataPoints().At(0).Attributes().PutStr("otel_scope_version", "v0.0.1")
case pmetric.MetricTypeSummary:
metric.Summary().DataPoints().At(0).Attributes().PutStr("otel_scope_name", "myscope")
metric.Summary().DataPoints().At(0).Attributes().PutStr("otel_scope_version", "v0.0.1")
}
}
return metrics
}(),
Expand Down Expand Up @@ -231,9 +282,83 @@ func TestAddExtraMetrics(t *testing.T) {
// and target_info (which will have an empty scope)
for i := 0; i < sm.Metrics().Len(); i++ {
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))
switch metric.Type() {
case pmetric.MetricTypeGauge:
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))
case pmetric.MetricTypeSum:
metric.Sum().DataPoints().At(0).Attributes().PutStr("otel_scope_name", "myscope")
metric.Sum().DataPoints().At(0).Attributes().PutStr("otel_scope_version", "v0.0.1")
metric.Sum().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp))
case pmetric.MetricTypeSummary:
metric.Summary().DataPoints().At(0).Attributes().PutStr("otel_scope_name", "myscope")
metric.Summary().DataPoints().At(0).Attributes().PutStr("otel_scope_version", "v0.0.1")
metric.Summary().DataPoints().At(0).SetTimestamp(pcommon.NewTimestampFromTime(timestamp))
}
}

return metrics
}(),
},
{
name: "metric as double",
config: Config{ExtraMetricsConfig: ExtraMetricsConfig{
EnableScopeInfo: true,
EnableTargetInfo: true,
}},
input: testMetric(timestamp),
enableDoubleFeatureGate: true,
expected: func() pmetric.ResourceMetricsSlice {
metrics := testMetric(timestamp).ResourceMetrics()
scopeMetrics := metrics.At(0).ScopeMetrics()

// Insert a new, empty ScopeMetricsSlice for this resource that will hold target_info
sm := scopeMetrics.AppendEmpty()
metric := sm.Metrics().AppendEmpty()
metric.SetName("target_info")
// This changes the value to double because of the feature gate.
metric.SetEmptyGauge().DataPoints().AppendEmpty().SetDoubleValue(1)
dashpole marked this conversation as resolved.
Show resolved Hide resolved
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)
scopeInfoMetric := sm.Metrics().AppendEmpty()
scopeInfoMetric.SetName("otel_scope_info")
// This changes the value to double because of the feature gate.
scopeInfoMetric.SetEmptyGauge().DataPoints().AppendEmpty().SetDoubleValue(1)

// add otel_scope_* attributes to all metrics in all scopes
// this includes otel_scope_info for the existing (input) ScopeMetrics,
// and target_info (which will have an empty scope)
for i := 0; i < sm.Metrics().Len(); i++ {
metric := sm.Metrics().At(i)
switch metric.Type() {
case pmetric.MetricTypeGauge:
dataPoint := metric.Gauge().DataPoints().At(0)
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))
// Change the original value to double
if dataPoint.IntValue() == 2112 {
dataPoint.SetDoubleValue(float64(2112.0))
}
case pmetric.MetricTypeSum:
dataPoint := metric.Sum().DataPoints().At(0)
dataPoint.Attributes().PutStr("otel_scope_name", "myscope")
dataPoint.Attributes().PutStr("otel_scope_version", "v0.0.1")
dataPoint.SetTimestamp(pcommon.NewTimestampFromTime(timestamp))
// Change the original value to double
if dataPoint.IntValue() == 2112 {
dataPoint.SetDoubleValue(float64(2112.0))
}
case pmetric.MetricTypeSummary:
dataPoint := metric.Summary().DataPoints().At(0)
dataPoint.Attributes().PutStr("otel_scope_name", "myscope")
dataPoint.Attributes().PutStr("otel_scope_version", "v0.0.1")
dataPoint.SetTimestamp(pcommon.NewTimestampFromTime(timestamp))
}
}

return metrics
Expand Down Expand Up @@ -339,7 +464,7 @@ func TestAddExtraMetrics(t *testing.T) {
Metadata().PutStr("prometheus.type", "unknown")

metric := metrics.At(0).ScopeMetrics().At(0).Metrics().AppendEmpty()
metric.SetName("baz-metric")
metric.SetName("gauge-metric")
metric.Metadata().PutStr("prometheus.type", "unknown")
metric.SetEmptySum().DataPoints().AppendEmpty().SetIntValue(2112)
metric.Sum().SetIsMonotonic(true)
Expand Down Expand Up @@ -375,7 +500,7 @@ func TestAddExtraMetrics(t *testing.T) {
Gauge().DataPoints().At(0).SetDoubleValue(123.5)

metric := metrics.At(0).ScopeMetrics().At(0).Metrics().AppendEmpty()
metric.SetName("baz-metric")
metric.SetName("gauge-metric")
metric.Metadata().PutStr("prometheus.type", "unknown")
metric.SetEmptySum().DataPoints().AppendEmpty().SetDoubleValue(123.5)
metric.Sum().SetIsMonotonic(true)
Expand Down Expand Up @@ -431,6 +556,11 @@ func TestAddExtraMetrics(t *testing.T) {
},
} {
t.Run(tc.name, func(t *testing.T) {
originalValue := intToDoubleFeatureGate.IsEnabled()
require.NoError(t, featuregate.GlobalRegistry().Set(intToDoubleFeatureGate.ID(), tc.enableDoubleFeatureGate))
defer func() {
require.NoError(t, featuregate.GlobalRegistry().Set(intToDoubleFeatureGate.ID(), originalValue))
}()
m := tc.input
tc.config.ExtraMetrics(m)
assert.EqualValues(t, tc.expected, m.ResourceMetrics())
Expand Down