diff --git a/.chloggen/feat_transformprocessor_histogram-convert.yaml b/.chloggen/feat_transformprocessor_histogram-convert.yaml new file mode 100755 index 000000000000..6f1651de63ca --- /dev/null +++ b/.chloggen/feat_transformprocessor_histogram-convert.yaml @@ -0,0 +1,20 @@ +# Use this changelog template to create an entry for release notes. +# If your change doesn't affect end users, such as a test fix or a tooling change, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. + +# 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: transformprocessor + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add extract_sum_metric OTTL function to transform processor + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [22853] + +# (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: diff --git a/processor/transformprocessor/README.md b/processor/transformprocessor/README.md index 2071ef00ca3f..bc1b6a66ef56 100644 --- a/processor/transformprocessor/README.md +++ b/processor/transformprocessor/README.md @@ -218,6 +218,30 @@ Examples: - `convert_gauge_to_sum("delta", true)` +### extract_sum_metric + +> [!NOTE] +> This function supports Histograms, ExponentialHistograms and Summaries. + +`extract_sum_metric(is_monotonic)` + +The `extract_sum_metric` function creates a new Sum metric from a Histogram, ExponentialHistogram or Summary's sum value. If the sum value of a Histogram or ExponentialHistogram data point is missing, no data point is added to the output metric. A metric will only be created if there is at least one data point. + +`is_monotonic` is a boolean representing the monotonicity of the new metric. + +The name for the new metric will be `_sum`. The fields that are copied are: `timestamp`, `starttimestamp`, `attibutes`, `description`, and `aggregation_temporality`. As metrics of type Summary don't have an `aggregation_temporality` field, this field will be set to `AGGREGATION_TEMPORALITY_CUMULATIVE` for those metrics. + +The new metric that is created will be passed to all subsequent statements in the metrics statements list. + +> [!WARNING] +> This function may cause a metric to break semantics for [Sum metrics](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/data-model.md#sums). Use only if you're confident you know what the resulting monotonicity should be. + +Examples: + +- `extract_sum_metric(true)` + +- `extract_sum_metric(false)` + ### convert_summary_count_val_to_sum `convert_summary_count_val_to_sum(aggregation_temporality, is_monotonic)` diff --git a/processor/transformprocessor/internal/metrics/func_convert_summary_sum_val_to_sum_test.go b/processor/transformprocessor/internal/metrics/func_convert_summary_sum_val_to_sum_test.go index d5a2fc85d7cf..af23a5a6c0f1 100644 --- a/processor/transformprocessor/internal/metrics/func_convert_summary_sum_val_to_sum_test.go +++ b/processor/transformprocessor/internal/metrics/func_convert_summary_sum_val_to_sum_test.go @@ -13,51 +13,6 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottldatapoint" ) -func getTestSummaryMetric() pmetric.Metric { - metricInput := pmetric.NewMetric() - metricInput.SetEmptySummary() - metricInput.SetName("summary_metric") - input := metricInput.Summary().DataPoints().AppendEmpty() - input.SetCount(100) - input.SetSum(12.34) - - qVal1 := input.QuantileValues().AppendEmpty() - qVal1.SetValue(1) - qVal1.SetQuantile(.99) - - qVal2 := input.QuantileValues().AppendEmpty() - qVal2.SetValue(2) - qVal2.SetQuantile(.95) - - qVal3 := input.QuantileValues().AppendEmpty() - qVal3.SetValue(3) - qVal3.SetQuantile(.50) - - attrs := getTestAttributes() - attrs.CopyTo(input.Attributes()) - return metricInput -} - -func getTestGaugeMetric() pmetric.Metric { - metricInput := pmetric.NewMetric() - metricInput.SetEmptyGauge() - metricInput.SetName("gauge_metric") - input := metricInput.Gauge().DataPoints().AppendEmpty() - input.SetIntValue(12) - - attrs := getTestAttributes() - attrs.CopyTo(input.Attributes()) - return metricInput -} - -func getTestAttributes() pcommon.Map { - attrs := pcommon.NewMap() - attrs.PutStr("test", "hello world") - attrs.PutInt("test2", 3) - attrs.PutBool("test3", true) - return attrs -} - type summaryTestCase struct { name string input pmetric.Metric diff --git a/processor/transformprocessor/internal/metrics/func_extract_sum_metric.go b/processor/transformprocessor/internal/metrics/func_extract_sum_metric.go new file mode 100644 index 000000000000..4ce39436bc18 --- /dev/null +++ b/processor/transformprocessor/internal/metrics/func_extract_sum_metric.go @@ -0,0 +1,112 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package metrics // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor/internal/metrics" + +import ( + "context" + "fmt" + + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/pmetric" + + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlmetric" +) + +type extractSumMetricArguments struct { + Monotonic bool `ottlarg:"0"` +} + +func newExtractSumMetricFactory() ottl.Factory[ottlmetric.TransformContext] { + return ottl.NewFactory("extract_sum_metric", &extractSumMetricArguments{}, createExtractSumMetricFunction) +} + +func createExtractSumMetricFunction(_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[ottlmetric.TransformContext], error) { + args, ok := oArgs.(*extractSumMetricArguments) + + if !ok { + return nil, fmt.Errorf("extractSumMetricFactory args must be of type *extractSumMetricArguments") + } + + return extractSumMetric(args.Monotonic) +} + +// this interface helps unify the logic for extracting data from different histogram types +// all supported metric types' datapoints implement it +type SumCountDataPoint interface { + Attributes() pcommon.Map + Sum() float64 + Count() uint64 + StartTimestamp() pcommon.Timestamp + Timestamp() pcommon.Timestamp +} + +func extractSumMetric(monotonic bool) (ottl.ExprFunc[ottlmetric.TransformContext], error) { + return func(_ context.Context, tCtx ottlmetric.TransformContext) (interface{}, error) { + var aggTemp pmetric.AggregationTemporality + metric := tCtx.GetMetric() + invalidMetricTypeError := fmt.Errorf("extract_sum_metric requires an input metric of type Histogram, ExponentialHistogram or Summary, got %s", metric.Type()) + + switch metric.Type() { + case pmetric.MetricTypeHistogram: + aggTemp = metric.Histogram().AggregationTemporality() + case pmetric.MetricTypeExponentialHistogram: + aggTemp = metric.ExponentialHistogram().AggregationTemporality() + case pmetric.MetricTypeSummary: + // Summaries don't have an aggregation temporality, but they *should* be cumulative based on the Openmetrics spec. + // This should become an optional argument once those are available in OTTL. + aggTemp = pmetric.AggregationTemporalityCumulative + default: + return nil, invalidMetricTypeError + } + + sumMetric := pmetric.NewMetric() + sumMetric.SetDescription(metric.Description()) + sumMetric.SetName(metric.Name() + "_sum") + sumMetric.SetUnit(metric.Unit()) + sumMetric.SetEmptySum().SetAggregationTemporality(aggTemp) + sumMetric.Sum().SetIsMonotonic(monotonic) + + switch metric.Type() { + case pmetric.MetricTypeHistogram: + dataPoints := metric.Histogram().DataPoints() + for i := 0; i < dataPoints.Len(); i++ { + dataPoint := dataPoints.At(i) + if dataPoint.HasSum() { + addSumDataPoint(dataPoint, sumMetric.Sum().DataPoints()) + } + } + case pmetric.MetricTypeExponentialHistogram: + dataPoints := metric.ExponentialHistogram().DataPoints() + for i := 0; i < dataPoints.Len(); i++ { + dataPoint := dataPoints.At(i) + if dataPoint.HasSum() { + addSumDataPoint(dataPoint, sumMetric.Sum().DataPoints()) + } + } + case pmetric.MetricTypeSummary: + dataPoints := metric.Summary().DataPoints() + // note that unlike Histograms, the Sum field is required for Summaries + for i := 0; i < dataPoints.Len(); i++ { + addSumDataPoint(dataPoints.At(i), sumMetric.Sum().DataPoints()) + } + default: + return nil, invalidMetricTypeError + } + + if sumMetric.Sum().DataPoints().Len() > 0 { + sumMetric.MoveTo(tCtx.GetMetrics().AppendEmpty()) + } + + return nil, nil + }, nil +} + +func addSumDataPoint(dataPoint SumCountDataPoint, destination pmetric.NumberDataPointSlice) { + newDp := destination.AppendEmpty() + dataPoint.Attributes().CopyTo(newDp.Attributes()) + newDp.SetDoubleValue(dataPoint.Sum()) + newDp.SetStartTimestamp(dataPoint.StartTimestamp()) + newDp.SetTimestamp(dataPoint.Timestamp()) +} diff --git a/processor/transformprocessor/internal/metrics/func_extract_sum_metric_test.go b/processor/transformprocessor/internal/metrics/func_extract_sum_metric_test.go new file mode 100644 index 000000000000..a2601675b67e --- /dev/null +++ b/processor/transformprocessor/internal/metrics/func_extract_sum_metric_test.go @@ -0,0 +1,297 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package metrics + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/pmetric" + + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlmetric" +) + +func getTestHistogramMetric() pmetric.Metric { + metricInput := pmetric.NewMetric() + metricInput.SetEmptyHistogram() + metricInput.SetName("histogram_metric") + metricInput.Histogram().SetAggregationTemporality(pmetric.AggregationTemporalityDelta) + input := metricInput.Histogram().DataPoints().AppendEmpty() + input.SetCount(5) + input.SetSum(12.34) + + input.BucketCounts().Append(2, 3) + input.ExplicitBounds().Append(1) + + attrs := getTestAttributes() + attrs.CopyTo(input.Attributes()) + return metricInput +} + +func getTestExponentialHistogramMetric() pmetric.Metric { + metricInput := pmetric.NewMetric() + metricInput.SetEmptyExponentialHistogram() + metricInput.SetName("exponential_histogram_metric") + metricInput.ExponentialHistogram().SetAggregationTemporality(pmetric.AggregationTemporalityDelta) + input := metricInput.ExponentialHistogram().DataPoints().AppendEmpty() + input.SetScale(1) + input.SetCount(5) + input.SetSum(12.34) + + attrs := getTestAttributes() + attrs.CopyTo(input.Attributes()) + return metricInput +} + +func getTestSummaryMetric() pmetric.Metric { + metricInput := pmetric.NewMetric() + metricInput.SetEmptySummary() + metricInput.SetName("summary_metric") + input := metricInput.Summary().DataPoints().AppendEmpty() + input.SetCount(100) + input.SetSum(12.34) + + qVal1 := input.QuantileValues().AppendEmpty() + qVal1.SetValue(1) + qVal1.SetQuantile(.99) + + qVal2 := input.QuantileValues().AppendEmpty() + qVal2.SetValue(2) + qVal2.SetQuantile(.95) + + qVal3 := input.QuantileValues().AppendEmpty() + qVal3.SetValue(3) + qVal3.SetQuantile(.50) + + attrs := getTestAttributes() + attrs.CopyTo(input.Attributes()) + return metricInput +} + +func getTestGaugeMetric() pmetric.Metric { + metricInput := pmetric.NewMetric() + metricInput.SetEmptyGauge() + metricInput.SetName("gauge_metric") + input := metricInput.Gauge().DataPoints().AppendEmpty() + input.SetIntValue(12) + + attrs := getTestAttributes() + attrs.CopyTo(input.Attributes()) + return metricInput +} + +func getTestAttributes() pcommon.Map { + attrs := pcommon.NewMap() + attrs.PutStr("test", "hello world") + attrs.PutInt("test2", 3) + attrs.PutBool("test3", true) + return attrs +} + +type histogramTestCase struct { + name string + input pmetric.Metric + monotonicity bool + want func(pmetric.MetricSlice) + wantErr error +} + +func Test_extractSumMetric(t *testing.T) { + tests := []histogramTestCase{ + { + name: "histogram (non-monotonic)", + input: getTestHistogramMetric(), + monotonicity: false, + want: func(metrics pmetric.MetricSlice) { + histogramMetric := getTestHistogramMetric() + histogramMetric.CopyTo(metrics.AppendEmpty()) + sumMetric := metrics.AppendEmpty() + sumMetric.SetEmptySum() + sumMetric.Sum().SetAggregationTemporality(histogramMetric.Histogram().AggregationTemporality()) + sumMetric.Sum().SetIsMonotonic(false) + + sumMetric.SetName(histogramMetric.Name() + "_sum") + dp := sumMetric.Sum().DataPoints().AppendEmpty() + dp.SetDoubleValue(histogramMetric.Histogram().DataPoints().At(0).Sum()) + + attrs := getTestAttributes() + attrs.CopyTo(dp.Attributes()) + }, + }, + { + name: "histogram (monotonic)", + input: getTestHistogramMetric(), + monotonicity: true, + want: func(metrics pmetric.MetricSlice) { + histogramMetric := getTestHistogramMetric() + histogramMetric.CopyTo(metrics.AppendEmpty()) + sumMetric := metrics.AppendEmpty() + sumMetric.SetEmptySum() + sumMetric.Sum().SetAggregationTemporality(histogramMetric.Histogram().AggregationTemporality()) + sumMetric.Sum().SetIsMonotonic(true) + + sumMetric.SetName(histogramMetric.Name() + "_sum") + dp := sumMetric.Sum().DataPoints().AppendEmpty() + dp.SetDoubleValue(histogramMetric.Histogram().DataPoints().At(0).Sum()) + + attrs := getTestAttributes() + attrs.CopyTo(dp.Attributes()) + }, + }, + { + name: "histogram (no sum)", + input: func() pmetric.Metric { + metric := getTestHistogramMetric() + metric.Histogram().DataPoints().At(0).RemoveSum() + return metric + }(), + monotonicity: true, + want: func(metrics pmetric.MetricSlice) { + histogramMetric := getTestHistogramMetric() + histogramMetric.Histogram().DataPoints().At(0).RemoveSum() + histogramMetric.CopyTo(metrics.AppendEmpty()) + }, + }, + { + name: "exponential histogram (non-monotonic)", + input: getTestExponentialHistogramMetric(), + monotonicity: false, + want: func(metrics pmetric.MetricSlice) { + expHistogramMetric := getTestExponentialHistogramMetric() + expHistogramMetric.CopyTo(metrics.AppendEmpty()) + sumMetric := metrics.AppendEmpty() + sumMetric.SetEmptySum() + sumMetric.Sum().SetAggregationTemporality(expHistogramMetric.ExponentialHistogram().AggregationTemporality()) + sumMetric.Sum().SetIsMonotonic(false) + + sumMetric.SetName(expHistogramMetric.Name() + "_sum") + dp := sumMetric.Sum().DataPoints().AppendEmpty() + dp.SetDoubleValue(expHistogramMetric.ExponentialHistogram().DataPoints().At(0).Sum()) + + attrs := getTestAttributes() + attrs.CopyTo(dp.Attributes()) + }, + }, + { + name: "exponential histogram (monotonic)", + input: getTestExponentialHistogramMetric(), + monotonicity: true, + want: func(metrics pmetric.MetricSlice) { + expHistogramMetric := getTestExponentialHistogramMetric() + expHistogramMetric.CopyTo(metrics.AppendEmpty()) + sumMetric := metrics.AppendEmpty() + sumMetric.SetEmptySum() + sumMetric.Sum().SetAggregationTemporality(expHistogramMetric.ExponentialHistogram().AggregationTemporality()) + sumMetric.Sum().SetIsMonotonic(true) + + sumMetric.SetName(expHistogramMetric.Name() + "_sum") + dp := sumMetric.Sum().DataPoints().AppendEmpty() + dp.SetDoubleValue(expHistogramMetric.ExponentialHistogram().DataPoints().At(0).Sum()) + + attrs := getTestAttributes() + attrs.CopyTo(dp.Attributes()) + }, + }, + { + name: "exponential histogram (non-monotonic)", + input: getTestExponentialHistogramMetric(), + monotonicity: false, + want: func(metrics pmetric.MetricSlice) { + expHistogramMetric := getTestExponentialHistogramMetric() + expHistogramMetric.CopyTo(metrics.AppendEmpty()) + sumMetric := metrics.AppendEmpty() + sumMetric.SetEmptySum() + sumMetric.Sum().SetAggregationTemporality(expHistogramMetric.ExponentialHistogram().AggregationTemporality()) + sumMetric.Sum().SetIsMonotonic(false) + + sumMetric.SetName(expHistogramMetric.Name() + "_sum") + dp := sumMetric.Sum().DataPoints().AppendEmpty() + dp.SetDoubleValue(expHistogramMetric.ExponentialHistogram().DataPoints().At(0).Sum()) + + attrs := getTestAttributes() + attrs.CopyTo(dp.Attributes()) + }, + }, + { + name: "exponential histogram (no sum)", + input: func() pmetric.Metric { + metric := getTestExponentialHistogramMetric() + metric.ExponentialHistogram().DataPoints().At(0).RemoveSum() + return metric + }(), + monotonicity: true, + want: func(metrics pmetric.MetricSlice) { + expHistogramMetric := getTestExponentialHistogramMetric() + expHistogramMetric.ExponentialHistogram().DataPoints().At(0).RemoveSum() + expHistogramMetric.CopyTo(metrics.AppendEmpty()) + }, + }, + { + name: "summary (non-monotonic)", + input: getTestSummaryMetric(), + monotonicity: false, + want: func(metrics pmetric.MetricSlice) { + summaryMetric := getTestSummaryMetric() + summaryMetric.CopyTo(metrics.AppendEmpty()) + sumMetric := metrics.AppendEmpty() + sumMetric.SetEmptySum() + sumMetric.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) + sumMetric.Sum().SetIsMonotonic(false) + + sumMetric.SetName("summary_metric_sum") + dp := sumMetric.Sum().DataPoints().AppendEmpty() + dp.SetDoubleValue(12.34) + + attrs := getTestAttributes() + attrs.CopyTo(dp.Attributes()) + }, + }, + { + name: "summary (monotonic)", + input: getTestSummaryMetric(), + monotonicity: true, + want: func(metrics pmetric.MetricSlice) { + summaryMetric := getTestSummaryMetric() + summaryMetric.CopyTo(metrics.AppendEmpty()) + sumMetric := metrics.AppendEmpty() + sumMetric.SetEmptySum() + sumMetric.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) + sumMetric.Sum().SetIsMonotonic(true) + + sumMetric.SetName("summary_metric_sum") + dp := sumMetric.Sum().DataPoints().AppendEmpty() + dp.SetDoubleValue(12.34) + + attrs := getTestAttributes() + attrs.CopyTo(dp.Attributes()) + }, + }, + { + name: "gauge (error)", + input: getTestGaugeMetric(), + monotonicity: false, + wantErr: fmt.Errorf("extract_sum_metric requires an input metric of type Histogram, ExponentialHistogram or Summary, got Gauge"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actualMetrics := pmetric.NewMetricSlice() + tt.input.CopyTo(actualMetrics.AppendEmpty()) + + evaluate, err := extractSumMetric(tt.monotonicity) + assert.NoError(t, err) + + _, err = evaluate(nil, ottlmetric.NewTransformContext(tt.input, actualMetrics, pcommon.NewInstrumentationScope(), pcommon.NewResource())) + assert.Equal(t, tt.wantErr, err) + + if tt.want != nil { + expected := pmetric.NewMetricSlice() + tt.want(expected) + assert.Equal(t, expected, actualMetrics) + } + }) + } +} diff --git a/processor/transformprocessor/internal/metrics/functions.go b/processor/transformprocessor/internal/metrics/functions.go index 482f5abcf66b..47cce1be1708 100644 --- a/processor/transformprocessor/internal/metrics/functions.go +++ b/processor/transformprocessor/internal/metrics/functions.go @@ -28,5 +28,15 @@ func DataPointFunctions() map[string]ottl.Factory[ottldatapoint.TransformContext } func MetricFunctions() map[string]ottl.Factory[ottlmetric.TransformContext] { - return ottlfuncs.StandardFuncs[ottlmetric.TransformContext]() + functions := ottlfuncs.StandardFuncs[ottlmetric.TransformContext]() + + metricFunctions := ottl.CreateFactoryMap( + newExtractSumMetricFactory(), + ) + + for k, v := range metricFunctions { + functions[k] = v + + } + return functions } diff --git a/processor/transformprocessor/internal/metrics/functions_test.go b/processor/transformprocessor/internal/metrics/functions_test.go index 4e68eb2a8974..67723dbc2f72 100644 --- a/processor/transformprocessor/internal/metrics/functions_test.go +++ b/processor/transformprocessor/internal/metrics/functions_test.go @@ -31,6 +31,7 @@ func Test_DataPointFunctions(t *testing.T) { func Test_MetricFunctions(t *testing.T) { expected := ottlfuncs.StandardFuncs[ottlmetric.TransformContext]() + expected["extract_sum_metric"] = newExtractSumMetricFactory() actual := MetricFunctions() require.Equal(t, len(expected), len(actual)) for k := range actual { diff --git a/processor/transformprocessor/internal/metrics/processor_test.go b/processor/transformprocessor/internal/metrics/processor_test.go index 54086146de53..11178c970f26 100644 --- a/processor/transformprocessor/internal/metrics/processor_test.go +++ b/processor/transformprocessor/internal/metrics/processor_test.go @@ -94,6 +94,81 @@ func Test_ProcessMetrics_ScopeContext(t *testing.T) { } } +func Test_ProcessMetrics_MetricContext(t *testing.T) { + tests := []struct { + statements []string + want func(pmetric.Metrics) + }{ + { + statements: []string{`extract_sum_metric(true) where name == "operationB"`}, + want: func(td pmetric.Metrics) { + sumMetric := td.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().AppendEmpty() + sumDp := sumMetric.SetEmptySum().DataPoints().AppendEmpty() + + histogramMetric := pmetric.NewMetric() + fillMetricTwo(histogramMetric) + histogramDp := histogramMetric.Histogram().DataPoints().At(0) + + sumMetric.SetDescription(histogramMetric.Description()) + sumMetric.SetName(histogramMetric.Name() + "_sum") + sumMetric.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityDelta) + sumMetric.Sum().SetIsMonotonic(true) + sumMetric.SetUnit(histogramMetric.Unit()) + + histogramDp.Attributes().CopyTo(sumDp.Attributes()) + sumDp.SetDoubleValue(histogramDp.Sum()) + sumDp.SetStartTimestamp(StartTimestamp) + + // we have two histogram datapoints, but only one of them has the Sum set + // so we should only have one Sum datapoint + }, + }, + { // this checks if subsequent statements apply to the newly created metric + statements: []string{ + `extract_sum_metric(true) where name == "operationB"`, + `set(name, "new_name") where name == "operationB_sum"`, + }, + want: func(td pmetric.Metrics) { + sumMetric := td.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().AppendEmpty() + sumDp := sumMetric.SetEmptySum().DataPoints().AppendEmpty() + + histogramMetric := pmetric.NewMetric() + fillMetricTwo(histogramMetric) + histogramDp := histogramMetric.Histogram().DataPoints().At(0) + + sumMetric.SetDescription(histogramMetric.Description()) + sumMetric.SetName("new_name") + sumMetric.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityDelta) + sumMetric.Sum().SetIsMonotonic(true) + sumMetric.SetUnit(histogramMetric.Unit()) + + histogramDp.Attributes().CopyTo(sumDp.Attributes()) + sumDp.SetDoubleValue(histogramDp.Sum()) + sumDp.SetStartTimestamp(StartTimestamp) + + // we have two histogram datapoints, but only one of them has the Sum set + // so we should only have one Sum datapoint + }, + }, + } + + for _, tt := range tests { + t.Run(tt.statements[0], func(t *testing.T) { + td := constructMetrics() + processor, err := NewProcessor([]common.ContextStatements{{Context: "metric", Statements: tt.statements}}, ottl.IgnoreError, componenttest.NewNopTelemetrySettings()) + assert.NoError(t, err) + + _, err = processor.ProcessMetrics(context.Background(), td) + assert.NoError(t, err) + + exTd := constructMetrics() + tt.want(exTd) + + assert.Equal(t, exTd, td) + }) + } +} + func Test_ProcessMetrics_DataPointContext(t *testing.T) { tests := []struct { statements []string @@ -735,8 +810,10 @@ func fillMetricTwo(m pmetric.Metric) { m.SetName("operationB") m.SetDescription("operationB description") m.SetUnit("operationB unit") + m.SetEmptyHistogram() + m.Histogram().SetAggregationTemporality(pmetric.AggregationTemporalityDelta) - dataPoint0 := m.SetEmptyHistogram().DataPoints().AppendEmpty() + dataPoint0 := m.Histogram().DataPoints().AppendEmpty() dataPoint0.SetStartTimestamp(StartTimestamp) dataPoint0.Attributes().PutStr("attr1", "test1") dataPoint0.Attributes().PutStr("attr2", "test2") @@ -744,6 +821,7 @@ func fillMetricTwo(m pmetric.Metric) { dataPoint0.Attributes().PutStr("flags", "C|D") dataPoint0.Attributes().PutStr("total.string", "345678") dataPoint0.SetCount(1) + dataPoint0.SetSum(5) dataPoint1 := m.Histogram().DataPoints().AppendEmpty() dataPoint1.SetStartTimestamp(StartTimestamp)