Skip to content

Commit

Permalink
add feature gate to convert int metrics to double
Browse files Browse the repository at this point in the history
  • Loading branch information
dashpole committed May 3, 2024
1 parent bda7f02 commit 6a683fd
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 4 deletions.
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()

Check warning on line 59 in exporter/collector/googlemanagedprometheus/extra_metrics.go

View check run for this annotation

Codecov / codecov/patch

exporter/collector/googlemanagedprometheus/extra_metrics.go#L58-L59

Added lines #L58 - L59 were not covered by tests
case pmetric.MetricTypeGauge:
points = metric.Gauge().DataPoints()
default:
continue

Check warning on line 63 in exporter/collector/googlemanagedprometheus/extra_metrics.go

View check run for this annotation

Codecov / codecov/patch

exporter/collector/googlemanagedprometheus/extra_metrics.go#L62-L63

Added lines #L62 - L63 were not covered by tests
}
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
62 changes: 58 additions & 4 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 Down Expand Up @@ -52,10 +54,11 @@ func appendMetric(metrics pmetric.Metrics, timestamp time.Time) pmetric.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 @@ -239,6 +242,52 @@ func TestAddExtraMetrics(t *testing.T) {
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)
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)
dataPoint := metric.Gauge().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))
}
}

return metrics
}(),
},
{
name: "scope info for other metric types",
config: Config{ExtraMetricsConfig: ExtraMetricsConfig{EnableScopeInfo: true}},
Expand Down Expand Up @@ -431,6 +480,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

0 comments on commit 6a683fd

Please sign in to comment.