diff --git a/.chloggen/routing-by-datapoints-2.yaml b/.chloggen/routing-by-datapoints-2.yaml new file mode 100644 index 000000000000..12144704d843 --- /dev/null +++ b/.chloggen/routing-by-datapoints-2.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# 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: routingconnector + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add abiilty to route by 'datapoint' context + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [36523] + +# (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: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/connector/routingconnector/README.md b/connector/routingconnector/README.md index d7a3a7731419..0198da0978ee 100644 --- a/connector/routingconnector/README.md +++ b/connector/routingconnector/README.md @@ -33,7 +33,7 @@ If you are not already familiar with connectors, you may find it helpful to firs The following settings are available: - `table (required)`: the routing table for this connector. -- `table.context (optional, default: resource)`: the [OTTL Context] in which the statement will be evaluated. Currently, only `resource`, `span`, `metric`, `log`, and `request` are supported. +- `table.context (optional, default: resource)`: the [OTTL Context] in which the statement will be evaluated. Currently, only `resource`, `span`, `metric`, `datapoint`, `log`, and `request` are supported. - `table.statement`: the routing condition provided as the [OTTL] statement. Required if `table.condition` is not provided. May not be used for `request` context. - `table.condition`: the routing condition provided as the [OTTL] condition. Required if `table.statement` is not provided. Required for `request` context. - `table.pipelines (required)`: the list of pipelines to use when the routing condition is met. @@ -43,7 +43,7 @@ The following settings are available: ### Limitations -- The `match_once` setting is only supported when using the `resource` context. If any routes use `span`, `metric`, `log` or `request` context, `match_once` must be set to `true`. +- The `match_once` setting is only supported when using the `resource` context. If any routes use `span`, `metric`, `datapoint`, `log` or `request` context, `match_once` must be set to `true`. - The `request` context requires use of the `condition` setting, and relies on a very limited grammar. Conditions must be in the form of `request["key"] == "value"` or `request["key"] != "value"`. (In the future, this grammar may be expanded to support more complex conditions.) ### Supported [OTTL] functions diff --git a/connector/routingconnector/config.go b/connector/routingconnector/config.go index 33a0c702bca9..b3d5add7160e 100644 --- a/connector/routingconnector/config.go +++ b/connector/routingconnector/config.go @@ -77,7 +77,7 @@ func (c *Config) Validate() error { return err } fallthrough - case "span", "metric", "log": // ok + case "span", "metric", "datapoint", "log": // ok if !c.MatchOnce { return fmt.Errorf(`%q context is not supported with "match_once: false"`, item.Context) } diff --git a/connector/routingconnector/config_test.go b/connector/routingconnector/config_test.go index 4a0ef0d0d5a4..7356804005d8 100644 --- a/connector/routingconnector/config_test.go +++ b/connector/routingconnector/config_test.go @@ -250,6 +250,22 @@ func TestValidateConfig(t *testing.T) { }, error: `"metric" context is not supported with "match_once: false"`, }, + { + name: "datapoint context with match_once false", + config: &Config{ + MatchOnce: false, + Table: []RoutingTableItem{ + { + Context: "datapoint", + Statement: `route() where attributes["attr"] == "acme"`, + Pipelines: []pipeline.ID{ + pipeline.NewIDWithName(pipeline.SignalTraces, "otlp"), + }, + }, + }, + }, + error: `"datapoint" context is not supported with "match_once: false"`, + }, { name: "log context with match_once false", config: &Config{ diff --git a/connector/routingconnector/internal/pmetricutil/metrics.go b/connector/routingconnector/internal/pmetricutil/metrics.go index 58199dc02fe8..3744506405de 100644 --- a/connector/routingconnector/internal/pmetricutil/metrics.go +++ b/connector/routingconnector/internal/pmetricutil/metrics.go @@ -59,3 +59,196 @@ func MoveMetricsWithContextIf(from, to pmetric.Metrics, f func(pmetric.ResourceM return rm.ScopeMetrics().Len() == 0 }) } + +// MoveDataPointsWithContextIf calls f sequentially for each DataPoint present in the first pmetric.Metrics. +// If f returns true, the element is removed from the first pmetric.Metrics and added to the second pmetric.Metrics. +// Notably, the Resource, Scope, and Metric associated with the DataPoint are created in the second pmetric.Metrics only once. +// Resources, Scopes, or Metrics are removed from the original if they become empty. All ordering is preserved. +func MoveDataPointsWithContextIf(from, to pmetric.Metrics, f func(pmetric.ResourceMetrics, pmetric.ScopeMetrics, pmetric.Metric, any) bool) { + rms := from.ResourceMetrics() + for i := 0; i < rms.Len(); i++ { + rm := rms.At(i) + sms := rm.ScopeMetrics() + var rmCopy *pmetric.ResourceMetrics + for j := 0; j < sms.Len(); j++ { + sm := sms.At(j) + ms := sm.Metrics() + var smCopy *pmetric.ScopeMetrics + for k := 0; k < ms.Len(); k++ { + m := ms.At(k) + var mCopy *pmetric.Metric + + // TODO condense this code + switch m.Type() { + case pmetric.MetricTypeGauge: + dps := m.Gauge().DataPoints() + dps.RemoveIf(func(dp pmetric.NumberDataPoint) bool { + if !f(rm, sm, m, dp) { + return false + } + if rmCopy == nil { + rmc := to.ResourceMetrics().AppendEmpty() + rmCopy = &rmc + rm.Resource().CopyTo(rmCopy.Resource()) + rmCopy.SetSchemaUrl(rm.SchemaUrl()) + } + if smCopy == nil { + smc := rmCopy.ScopeMetrics().AppendEmpty() + smCopy = &smc + sm.Scope().CopyTo(smCopy.Scope()) + smCopy.SetSchemaUrl(sm.SchemaUrl()) + } + if mCopy == nil { + mc := smCopy.Metrics().AppendEmpty() + mCopy = &mc + mCopy.SetName(m.Name()) + mCopy.SetDescription(m.Description()) + mCopy.SetUnit(m.Unit()) + mCopy.SetEmptyGauge() + } + dp.CopyTo(mCopy.Gauge().DataPoints().AppendEmpty()) + return true + }) + case pmetric.MetricTypeSum: + dps := m.Sum().DataPoints() + dps.RemoveIf(func(dp pmetric.NumberDataPoint) bool { + if !f(rm, sm, m, dp) { + return false + } + if rmCopy == nil { + rmc := to.ResourceMetrics().AppendEmpty() + rmCopy = &rmc + rm.Resource().CopyTo(rmCopy.Resource()) + rmCopy.SetSchemaUrl(rm.SchemaUrl()) + } + if smCopy == nil { + smc := rmCopy.ScopeMetrics().AppendEmpty() + smCopy = &smc + sm.Scope().CopyTo(smCopy.Scope()) + smCopy.SetSchemaUrl(sm.SchemaUrl()) + } + if mCopy == nil { + mc := smCopy.Metrics().AppendEmpty() + mCopy = &mc + mCopy.SetName(m.Name()) + mCopy.SetDescription(m.Description()) + mCopy.SetUnit(m.Unit()) + mCopy.SetEmptySum() + } + dp.CopyTo(mCopy.Sum().DataPoints().AppendEmpty()) + return true + }) + case pmetric.MetricTypeHistogram: + dps := m.Histogram().DataPoints() + dps.RemoveIf(func(dp pmetric.HistogramDataPoint) bool { + if !f(rm, sm, m, dp) { + return false + } + if rmCopy == nil { + rmc := to.ResourceMetrics().AppendEmpty() + rmCopy = &rmc + rm.Resource().CopyTo(rmCopy.Resource()) + rmCopy.SetSchemaUrl(rm.SchemaUrl()) + } + if smCopy == nil { + smc := rmCopy.ScopeMetrics().AppendEmpty() + smCopy = &smc + sm.Scope().CopyTo(smCopy.Scope()) + smCopy.SetSchemaUrl(sm.SchemaUrl()) + } + if mCopy == nil { + mc := smCopy.Metrics().AppendEmpty() + mCopy = &mc + mCopy.SetName(m.Name()) + mCopy.SetDescription(m.Description()) + mCopy.SetUnit(m.Unit()) + mCopy.SetEmptyHistogram() + } + dp.CopyTo(mCopy.Histogram().DataPoints().AppendEmpty()) + return true + }) + case pmetric.MetricTypeExponentialHistogram: + dps := m.ExponentialHistogram().DataPoints() + dps.RemoveIf(func(dp pmetric.ExponentialHistogramDataPoint) bool { + if !f(rm, sm, m, dp) { + return false + } + if rmCopy == nil { + rmc := to.ResourceMetrics().AppendEmpty() + rmCopy = &rmc + rm.Resource().CopyTo(rmCopy.Resource()) + rmCopy.SetSchemaUrl(rm.SchemaUrl()) + } + if smCopy == nil { + smc := rmCopy.ScopeMetrics().AppendEmpty() + smCopy = &smc + sm.Scope().CopyTo(smCopy.Scope()) + smCopy.SetSchemaUrl(sm.SchemaUrl()) + } + if mCopy == nil { + mc := smCopy.Metrics().AppendEmpty() + mCopy = &mc + mCopy.SetName(m.Name()) + mCopy.SetDescription(m.Description()) + mCopy.SetUnit(m.Unit()) + mCopy.SetEmptyExponentialHistogram() + } + dp.CopyTo(mCopy.ExponentialHistogram().DataPoints().AppendEmpty()) + return true + }) + case pmetric.MetricTypeSummary: + dps := m.Summary().DataPoints() + dps.RemoveIf(func(dp pmetric.SummaryDataPoint) bool { + if !f(rm, sm, m, dp) { + return false + } + if rmCopy == nil { + rmc := to.ResourceMetrics().AppendEmpty() + rmCopy = &rmc + rm.Resource().CopyTo(rmCopy.Resource()) + rmCopy.SetSchemaUrl(rm.SchemaUrl()) + } + if smCopy == nil { + smc := rmCopy.ScopeMetrics().AppendEmpty() + smCopy = &smc + sm.Scope().CopyTo(smCopy.Scope()) + smCopy.SetSchemaUrl(sm.SchemaUrl()) + } + if mCopy == nil { + mc := smCopy.Metrics().AppendEmpty() + mCopy = &mc + mCopy.SetName(m.Name()) + mCopy.SetDescription(m.Description()) + mCopy.SetUnit(m.Unit()) + mCopy.SetEmptySummary() + } + dp.CopyTo(mCopy.Summary().DataPoints().AppendEmpty()) + return true + }) + } + } + ms.RemoveIf(func(m pmetric.Metric) bool { + var numDPs int + switch m.Type() { + case pmetric.MetricTypeGauge: + numDPs = m.Gauge().DataPoints().Len() + case pmetric.MetricTypeSum: + numDPs = m.Sum().DataPoints().Len() + case pmetric.MetricTypeHistogram: + numDPs = m.Histogram().DataPoints().Len() + case pmetric.MetricTypeExponentialHistogram: + numDPs = m.ExponentialHistogram().DataPoints().Len() + case pmetric.MetricTypeSummary: + numDPs = m.Summary().DataPoints().Len() + } + return numDPs == 0 + }) + } + sms.RemoveIf(func(sm pmetric.ScopeMetrics) bool { + return sm.Metrics().Len() == 0 + }) + } + rms.RemoveIf(func(rm pmetric.ResourceMetrics) bool { + return rm.ScopeMetrics().Len() == 0 + }) +} diff --git a/connector/routingconnector/internal/pmetricutil/metrics_test.go b/connector/routingconnector/internal/pmetricutil/metrics_test.go index 1eff9bc21201..371377cf33bb 100644 --- a/connector/routingconnector/internal/pmetricutil/metrics_test.go +++ b/connector/routingconnector/internal/pmetricutil/metrics_test.go @@ -28,9 +28,9 @@ func TestMoveResourcesIf(t *testing.T) { moveIf: func(pmetric.ResourceMetrics) bool { return false }, - from: pmetricutiltest.NewMetrics("AB", "CD", "EF", "FG"), + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "FG"), to: pmetric.NewMetrics(), - expectFrom: pmetricutiltest.NewMetrics("AB", "CD", "EF", "FG"), + expectFrom: pmetricutiltest.NewGauges("AB", "CD", "EF", "FG"), expectTo: pmetric.NewMetrics(), }, { @@ -38,10 +38,10 @@ func TestMoveResourcesIf(t *testing.T) { moveIf: func(pmetric.ResourceMetrics) bool { return true }, - from: pmetricutiltest.NewMetrics("AB", "CD", "EF", "FG"), + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "FG"), to: pmetric.NewMetrics(), expectFrom: pmetric.NewMetrics(), - expectTo: pmetricutiltest.NewMetrics("AB", "CD", "EF", "FG"), + expectTo: pmetricutiltest.NewGauges("AB", "CD", "EF", "FG"), }, { name: "move_one", @@ -49,10 +49,10 @@ func TestMoveResourcesIf(t *testing.T) { rname, ok := rl.Resource().Attributes().Get("resourceName") return ok && rname.AsString() == "resourceA" }, - from: pmetricutiltest.NewMetrics("AB", "CD", "EF", "FG"), + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "FG"), to: pmetric.NewMetrics(), - expectFrom: pmetricutiltest.NewMetrics("B", "CD", "EF", "FG"), - expectTo: pmetricutiltest.NewMetrics("A", "CD", "EF", "FG"), + expectFrom: pmetricutiltest.NewGauges("B", "CD", "EF", "FG"), + expectTo: pmetricutiltest.NewGauges("A", "CD", "EF", "FG"), }, { name: "move_to_preexisting", @@ -60,12 +60,12 @@ func TestMoveResourcesIf(t *testing.T) { rname, ok := rl.Resource().Attributes().Get("resourceName") return ok && rname.AsString() == "resourceB" }, - from: pmetricutiltest.NewMetrics("AB", "CD", "EF", "FG"), - to: pmetricutiltest.NewMetrics("1", "2", "3", "4"), - expectFrom: pmetricutiltest.NewMetrics("A", "CD", "EF", "FG"), + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "FG"), + to: pmetricutiltest.NewGauges("1", "2", "3", "4"), + expectFrom: pmetricutiltest.NewGauges("A", "CD", "EF", "FG"), expectTo: func() pmetric.Metrics { - move := pmetricutiltest.NewMetrics("B", "CD", "EF", "FG") - moveTo := pmetricutiltest.NewMetrics("1", "2", "3", "4") + move := pmetricutiltest.NewGauges("B", "CD", "EF", "FG") + moveTo := pmetricutiltest.NewGauges("1", "2", "3", "4") move.ResourceMetrics().MoveAndAppendTo(moveTo.ResourceMetrics()) return moveTo }(), @@ -95,9 +95,9 @@ func TestMoveMetricsWithContextIf(t *testing.T) { moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric) bool { return false }, - from: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), to: pmetric.NewMetrics(), - expectFrom: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + expectFrom: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectTo: pmetric.NewMetrics(), }, { @@ -105,10 +105,10 @@ func TestMoveMetricsWithContextIf(t *testing.T) { moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric) bool { return true }, - from: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), to: pmetric.NewMetrics(), expectFrom: pmetric.NewMetrics(), - expectTo: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + expectTo: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), }, { name: "move_all_from_one_resource", @@ -116,10 +116,10 @@ func TestMoveMetricsWithContextIf(t *testing.T) { rname, ok := rl.Resource().Attributes().Get("resourceName") return ok && rname.AsString() == "resourceB" }, - from: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), to: pmetric.NewMetrics(), - expectFrom: pmetricutiltest.NewMetrics("A", "CD", "EF", "GH"), - expectTo: pmetricutiltest.NewMetrics("B", "CD", "EF", "GH"), + expectFrom: pmetricutiltest.NewGauges("A", "CD", "EF", "GH"), + expectTo: pmetricutiltest.NewGauges("B", "CD", "EF", "GH"), }, { name: "move_all_from_one_scope", @@ -127,37 +127,37 @@ func TestMoveMetricsWithContextIf(t *testing.T) { rname, ok := rl.Resource().Attributes().Get("resourceName") return ok && rname.AsString() == "resourceB" && sl.Scope().Name() == "scopeC" }, - from: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), to: pmetric.NewMetrics(), expectFrom: pmetricutiltest.NewMetricsFromOpts( pmetricutiltest.Resource("A", pmetricutiltest.Scope("C", - pmetricutiltest.Metric("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), - pmetricutiltest.Metric("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), ), pmetricutiltest.Scope("D", - pmetricutiltest.Metric("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), - pmetricutiltest.Metric("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), ), ), pmetricutiltest.Resource("B", pmetricutiltest.Scope("D", - pmetricutiltest.Metric("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), - pmetricutiltest.Metric("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), ), ), ), - expectTo: pmetricutiltest.NewMetrics("B", "C", "EF", "GH"), + expectTo: pmetricutiltest.NewGauges("B", "C", "EF", "GH"), }, { name: "move_all_from_one_scope_in_each_resource", moveIf: func(_ pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, _ pmetric.Metric) bool { return sl.Scope().Name() == "scopeD" }, - from: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), to: pmetric.NewMetrics(), - expectFrom: pmetricutiltest.NewMetrics("AB", "C", "EF", "GH"), - expectTo: pmetricutiltest.NewMetrics("AB", "D", "EF", "GH"), + expectFrom: pmetricutiltest.NewGauges("AB", "C", "EF", "GH"), + expectTo: pmetricutiltest.NewGauges("AB", "D", "EF", "GH"), }, { name: "move_one", @@ -165,40 +165,40 @@ func TestMoveMetricsWithContextIf(t *testing.T) { rname, ok := rl.Resource().Attributes().Get("resourceName") return ok && rname.AsString() == "resourceA" && sl.Scope().Name() == "scopeD" && m.Name() == "metricF" }, - from: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), to: pmetric.NewMetrics(), expectFrom: pmetricutiltest.NewMetricsFromOpts( pmetricutiltest.Resource("A", pmetricutiltest.Scope("C", - pmetricutiltest.Metric("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), - pmetricutiltest.Metric("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), ), pmetricutiltest.Scope("D", - pmetricutiltest.Metric("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), ), ), pmetricutiltest.Resource("B", pmetricutiltest.Scope("C", - pmetricutiltest.Metric("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), - pmetricutiltest.Metric("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), ), pmetricutiltest.Scope("D", - pmetricutiltest.Metric("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), - pmetricutiltest.Metric("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), ), ), ), - expectTo: pmetricutiltest.NewMetrics("A", "D", "F", "GH"), + expectTo: pmetricutiltest.NewGauges("A", "D", "F", "GH"), }, { name: "move_one_from_each_scope", moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric) bool { return m.Name() == "metricE" }, - from: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), to: pmetric.NewMetrics(), - expectFrom: pmetricutiltest.NewMetrics("AB", "CD", "F", "GH"), - expectTo: pmetricutiltest.NewMetrics("AB", "CD", "E", "GH"), + expectFrom: pmetricutiltest.NewGauges("AB", "CD", "F", "GH"), + expectTo: pmetricutiltest.NewGauges("AB", "CD", "E", "GH"), }, { name: "move_one_from_each_scope_in_one_resource", @@ -206,49 +206,49 @@ func TestMoveMetricsWithContextIf(t *testing.T) { rname, ok := rl.Resource().Attributes().Get("resourceName") return ok && rname.AsString() == "resourceB" && m.Name() == "metricE" }, - from: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), to: pmetric.NewMetrics(), expectFrom: pmetricutiltest.NewMetricsFromOpts( pmetricutiltest.Resource("A", pmetricutiltest.Scope("C", - pmetricutiltest.Metric("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), - pmetricutiltest.Metric("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), ), pmetricutiltest.Scope("D", - pmetricutiltest.Metric("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), - pmetricutiltest.Metric("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), ), ), pmetricutiltest.Resource("B", pmetricutiltest.Scope("C", - pmetricutiltest.Metric("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), ), pmetricutiltest.Scope("D", - pmetricutiltest.Metric("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), ), ), ), - expectTo: pmetricutiltest.NewMetrics("B", "CD", "E", "GH"), + expectTo: pmetricutiltest.NewGauges("B", "CD", "E", "GH"), }, { name: "move_some_to_preexisting", moveIf: func(_ pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, _ pmetric.Metric) bool { return sl.Scope().Name() == "scopeD" }, - from: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - to: pmetricutiltest.NewMetrics("1", "2", "3", "4"), - expectFrom: pmetricutiltest.NewMetrics("AB", "C", "EF", "GH"), + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + to: pmetricutiltest.NewGauges("1", "2", "3", "4"), + expectFrom: pmetricutiltest.NewGauges("AB", "C", "EF", "GH"), expectTo: pmetricutiltest.NewMetricsFromOpts( pmetricutiltest.Resource("1", pmetricutiltest.Scope("2", - pmetricutiltest.Metric("3", pmetricutiltest.NumberDataPoint("4")), + pmetricutiltest.Gauge("3", pmetricutiltest.NumberDataPoint("4")), )), pmetricutiltest.Resource("A", pmetricutiltest.Scope("D", - pmetricutiltest.Metric("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), - pmetricutiltest.Metric("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), )), pmetricutiltest.Resource("B", pmetricutiltest.Scope("D", - pmetricutiltest.Metric("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), - pmetricutiltest.Metric("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), )), ), }, @@ -262,3 +262,1247 @@ func TestMoveMetricsWithContextIf(t *testing.T) { }) } } + +func TestMoveDataPointsWithContextIf(t *testing.T) { + testCases := []struct { + name string + moveIf func(pmetric.ResourceMetrics, pmetric.ScopeMetrics, pmetric.Metric, any) bool + from pmetric.Metrics + to pmetric.Metrics + expectFrom pmetric.Metrics + expectTo pmetric.Metrics + }{ + // gauge + { + name: "gauge/move_none", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + return false + }, + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectTo: pmetric.NewMetrics(), + }, + { + name: "gauge/move_all", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + return true + }, + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetric.NewMetrics(), + expectTo: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + }, + { + name: "gauge/move_all_from_one_resource", + moveIf: func(rl pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + rname, ok := rl.Resource().Attributes().Get("resourceName") + return ok && rname.AsString() == "resourceB" + }, + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewGauges("A", "CD", "EF", "GH"), + expectTo: pmetricutiltest.NewGauges("B", "CD", "EF", "GH"), + }, + { + name: "gauge/move_all_from_one_scope", + moveIf: func(rl pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + rname, ok := rl.Resource().Attributes().Get("resourceName") + return ok && rname.AsString() == "resourceB" && sl.Scope().Name() == "scopeC" + }, + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("D", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewGauges("B", "C", "EF", "GH"), + }, + { + name: "gauge/move_all_from_one_metric", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, _ any) bool { + return m.Name() == "metricE" + }, + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewGauges("AB", "CD", "F", "GH"), + expectTo: pmetricutiltest.NewGauges("AB", "CD", "E", "GH"), + }, + { + name: "gauge/move_all_from_one_scope_in_each_resource", + moveIf: func(_ pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + return sl.Scope().Name() == "scopeD" + }, + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewGauges("AB", "C", "EF", "GH"), + expectTo: pmetricutiltest.NewGauges("AB", "D", "EF", "GH"), + }, + { + name: "gauge/move_all_from_one_metric_in_each_scope", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, _ any) bool { + return m.Name() == "metricF" + }, + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewGauges("AB", "CD", "E", "GH"), + expectTo: pmetricutiltest.NewGauges("AB", "CD", "F", "GH"), + }, + { + name: "gauge/move_one", + moveIf: func(rl pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, m pmetric.Metric, dp any) bool { + rname, ok1 := rl.Resource().Attributes().Get("resourceName") + dpname, ok2 := dp.(pmetric.NumberDataPoint).Attributes().Get("dpName") + return ok1 && ok2 && rname.AsString() == "resourceA" && sl.Scope().Name() == "scopeD" && m.Name() == "metricF" && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewGauges("A", "D", "F", "G"), + }, + { + name: "gauge/move_one_from_each_resource", + moveIf: func(_ pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, m pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.NumberDataPoint).Attributes().Get("dpName") + return ok && sl.Scope().Name() == "scopeD" && m.Name() == "metricE" && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewGauges("AB", "D", "E", "G"), + }, + { + name: "gauge/move_one_from_each_scope", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.NumberDataPoint).Attributes().Get("dpName") + return ok && m.Name() == "metricE" && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewGauges("AB", "CD", "E", "G"), + }, + { + name: "gauge/move_one_from_each_metric", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.NumberDataPoint).Attributes().Get("dpName") + return ok && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewGauges("AB", "CD", "EF", "H"), + expectTo: pmetricutiltest.NewGauges("AB", "CD", "EF", "G"), + }, + { + name: "gauge/move_one_from_each_scope_in_one_resource", + moveIf: func(rl pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, _ any) bool { + rname, ok := rl.Resource().Attributes().Get("resourceName") + return ok && rname.AsString() == "resourceB" && m.Name() == "metricE" + }, + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewGauges("B", "CD", "E", "GH"), + }, + { + name: "gauge/move_some_to_preexisting", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.NumberDataPoint).Attributes().Get("dpName") + return ok && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + to: pmetricutiltest.NewGauges("1", "2", "3", "4"), + expectFrom: pmetricutiltest.NewGauges("AB", "CD", "EF", "H"), + expectTo: func() pmetric.Metrics { + orig := pmetricutiltest.NewGauges("1", "2", "3", "4") + extra := pmetricutiltest.NewGauges("AB", "CD", "EF", "G") + extra.ResourceMetrics().MoveAndAppendTo(orig.ResourceMetrics()) + return orig + }(), + }, + + // sum + { + name: "sum/move_none", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + return false + }, + from: pmetricutiltest.NewSums("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewSums("AB", "CD", "EF", "GH"), + expectTo: pmetric.NewMetrics(), + }, + { + name: "sum/move_all", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + return true + }, + from: pmetricutiltest.NewSums("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetric.NewMetrics(), + expectTo: pmetricutiltest.NewSums("AB", "CD", "EF", "GH"), + }, + { + name: "sum/move_all_from_one_resource", + moveIf: func(rl pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + rname, ok := rl.Resource().Attributes().Get("resourceName") + return ok && rname.AsString() == "resourceB" + }, + from: pmetricutiltest.NewSums("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewSums("A", "CD", "EF", "GH"), + expectTo: pmetricutiltest.NewSums("B", "CD", "EF", "GH"), + }, + { + name: "sum/move_all_from_one_scope", + moveIf: func(rl pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + rname, ok := rl.Resource().Attributes().Get("resourceName") + return ok && rname.AsString() == "resourceB" && sl.Scope().Name() == "scopeC" + }, + from: pmetricutiltest.NewSums("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("D", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewSums("B", "C", "EF", "GH"), + }, + { + name: "sum/move_all_from_one_metric", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, _ any) bool { + return m.Name() == "metricE" + }, + from: pmetricutiltest.NewSums("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewSums("AB", "CD", "F", "GH"), + expectTo: pmetricutiltest.NewSums("AB", "CD", "E", "GH"), + }, + { + name: "sum/move_all_from_one_scope_in_each_resource", + moveIf: func(_ pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + return sl.Scope().Name() == "scopeD" + }, + from: pmetricutiltest.NewSums("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewSums("AB", "C", "EF", "GH"), + expectTo: pmetricutiltest.NewSums("AB", "D", "EF", "GH"), + }, + { + name: "sum/move_all_from_one_metric_in_each_scope", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, _ any) bool { + return m.Name() == "metricF" + }, + from: pmetricutiltest.NewSums("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewSums("AB", "CD", "E", "GH"), + expectTo: pmetricutiltest.NewSums("AB", "CD", "F", "GH"), + }, + { + name: "sum/move_one", + moveIf: func(rl pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, m pmetric.Metric, dp any) bool { + rname, ok1 := rl.Resource().Attributes().Get("resourceName") + dpname, ok2 := dp.(pmetric.NumberDataPoint).Attributes().Get("dpName") + return ok1 && ok2 && rname.AsString() == "resourceA" && sl.Scope().Name() == "scopeD" && m.Name() == "metricF" && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewSums("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewSums("A", "D", "F", "G"), + }, + { + name: "sum/move_one_from_each_resource", + moveIf: func(_ pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, m pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.NumberDataPoint).Attributes().Get("dpName") + return ok && sl.Scope().Name() == "scopeD" && m.Name() == "metricE" && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewSums("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewSums("AB", "D", "E", "G"), + }, + { + name: "sum/move_one_from_each_scope", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.NumberDataPoint).Attributes().Get("dpName") + return ok && m.Name() == "metricE" && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewSums("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewSums("AB", "CD", "E", "G"), + }, + { + name: "sum/move_one_from_each_metric", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.NumberDataPoint).Attributes().Get("dpName") + return ok && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewSums("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewSums("AB", "CD", "EF", "H"), + expectTo: pmetricutiltest.NewSums("AB", "CD", "EF", "G"), + }, + { + name: "sum/move_one_from_each_scope_in_one_resource", + moveIf: func(rl pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, _ any) bool { + rname, ok := rl.Resource().Attributes().Get("resourceName") + return ok && rname.AsString() == "resourceB" && m.Name() == "metricE" + }, + from: pmetricutiltest.NewSums("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Sum("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Sum("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewSums("B", "CD", "E", "GH"), + }, + { + name: "sum/move_some_to_preexisting", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.NumberDataPoint).Attributes().Get("dpName") + return ok && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewSums("AB", "CD", "EF", "GH"), + to: pmetricutiltest.NewSums("1", "2", "3", "4"), + expectFrom: pmetricutiltest.NewSums("AB", "CD", "EF", "H"), + expectTo: func() pmetric.Metrics { + orig := pmetricutiltest.NewSums("1", "2", "3", "4") + extra := pmetricutiltest.NewSums("AB", "CD", "EF", "G") + extra.ResourceMetrics().MoveAndAppendTo(orig.ResourceMetrics()) + return orig + }(), + }, + + // histogram + { + name: "histogram/move_none", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + return false + }, + from: pmetricutiltest.NewHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewHistograms("AB", "CD", "EF", "GH"), + expectTo: pmetric.NewMetrics(), + }, + { + name: "histogram/move_all", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + return true + }, + from: pmetricutiltest.NewHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetric.NewMetrics(), + expectTo: pmetricutiltest.NewHistograms("AB", "CD", "EF", "GH"), + }, + { + name: "histogram/move_all_from_one_resource", + moveIf: func(rl pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + rname, ok := rl.Resource().Attributes().Get("resourceName") + return ok && rname.AsString() == "resourceB" + }, + from: pmetricutiltest.NewHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewHistograms("A", "CD", "EF", "GH"), + expectTo: pmetricutiltest.NewHistograms("B", "CD", "EF", "GH"), + }, + { + name: "histogram/move_all_from_one_scope", + moveIf: func(rl pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + rname, ok := rl.Resource().Attributes().Get("resourceName") + return ok && rname.AsString() == "resourceB" && sl.Scope().Name() == "scopeC" + }, + from: pmetricutiltest.NewHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("D", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewHistograms("B", "C", "EF", "GH"), + }, + { + name: "histogram/move_all_from_one_metric", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, _ any) bool { + return m.Name() == "metricE" + }, + from: pmetricutiltest.NewHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewHistograms("AB", "CD", "F", "GH"), + expectTo: pmetricutiltest.NewHistograms("AB", "CD", "E", "GH"), + }, + { + name: "histogram/move_all_from_one_scope_in_each_resource", + moveIf: func(_ pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + return sl.Scope().Name() == "scopeD" + }, + from: pmetricutiltest.NewHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewHistograms("AB", "C", "EF", "GH"), + expectTo: pmetricutiltest.NewHistograms("AB", "D", "EF", "GH"), + }, + { + name: "histogram/move_all_from_one_metric_in_each_scope", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, _ any) bool { + return m.Name() == "metricF" + }, + from: pmetricutiltest.NewHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewHistograms("AB", "CD", "E", "GH"), + expectTo: pmetricutiltest.NewHistograms("AB", "CD", "F", "GH"), + }, + { + name: "histogram/move_one", + moveIf: func(rl pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, m pmetric.Metric, dp any) bool { + rname, ok1 := rl.Resource().Attributes().Get("resourceName") + dpname, ok2 := dp.(pmetric.HistogramDataPoint).Attributes().Get("dpName") + return ok1 && ok2 && rname.AsString() == "resourceA" && sl.Scope().Name() == "scopeD" && m.Name() == "metricF" && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewHistograms("A", "D", "F", "G"), + }, + { + name: "histogram/move_one_from_each_resource", + moveIf: func(_ pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, m pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.HistogramDataPoint).Attributes().Get("dpName") + return ok && sl.Scope().Name() == "scopeD" && m.Name() == "metricE" && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewHistograms("AB", "D", "E", "G"), + }, + { + name: "histogram/move_one_from_each_scope", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.HistogramDataPoint).Attributes().Get("dpName") + return ok && m.Name() == "metricE" && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewHistograms("AB", "CD", "E", "G"), + }, + { + name: "histogram/move_one_from_each_metric", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.HistogramDataPoint).Attributes().Get("dpName") + return ok && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewHistograms("AB", "CD", "EF", "H"), + expectTo: pmetricutiltest.NewHistograms("AB", "CD", "EF", "G"), + }, + { + name: "histogram/move_one_from_each_scope_in_one_resource", + moveIf: func(rl pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, _ any) bool { + rname, ok := rl.Resource().Attributes().Get("resourceName") + return ok && rname.AsString() == "resourceB" && m.Name() == "metricE" + }, + from: pmetricutiltest.NewHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Histogram("F", pmetricutiltest.HistogramDataPoint("G"), pmetricutiltest.HistogramDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewHistograms("B", "CD", "E", "GH"), + }, + { + name: "histogram/move_some_to_preexisting", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.HistogramDataPoint).Attributes().Get("dpName") + return ok && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewHistograms("AB", "CD", "EF", "GH"), + to: pmetricutiltest.NewHistograms("1", "2", "3", "4"), + expectFrom: pmetricutiltest.NewHistograms("AB", "CD", "EF", "H"), + expectTo: func() pmetric.Metrics { + orig := pmetricutiltest.NewHistograms("1", "2", "3", "4") + extra := pmetricutiltest.NewHistograms("AB", "CD", "EF", "G") + extra.ResourceMetrics().MoveAndAppendTo(orig.ResourceMetrics()) + return orig + }(), + }, + + // exponential_histogram + { + name: "exponential_histogram/move_none", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + return false + }, + from: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "GH"), + expectTo: pmetric.NewMetrics(), + }, + { + name: "exponential_histogram/move_all", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + return true + }, + from: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetric.NewMetrics(), + expectTo: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "GH"), + }, + { + name: "exponential_histogram/move_all_from_one_resource", + moveIf: func(rl pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + rname, ok := rl.Resource().Attributes().Get("resourceName") + return ok && rname.AsString() == "resourceB" + }, + from: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewExponentialHistograms("A", "CD", "EF", "GH"), + expectTo: pmetricutiltest.NewExponentialHistograms("B", "CD", "EF", "GH"), + }, + { + name: "exponential_histogram/move_all_from_one_scope", + moveIf: func(rl pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + rname, ok := rl.Resource().Attributes().Get("resourceName") + return ok && rname.AsString() == "resourceB" && sl.Scope().Name() == "scopeC" + }, + from: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("D", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewExponentialHistograms("B", "C", "EF", "GH"), + }, + { + name: "exponential_histogram/move_all_from_one_metric", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, _ any) bool { + return m.Name() == "metricE" + }, + from: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewExponentialHistograms("AB", "CD", "F", "GH"), + expectTo: pmetricutiltest.NewExponentialHistograms("AB", "CD", "E", "GH"), + }, + { + name: "exponential_histogram/move_all_from_one_scope_in_each_resource", + moveIf: func(_ pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + return sl.Scope().Name() == "scopeD" + }, + from: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewExponentialHistograms("AB", "C", "EF", "GH"), + expectTo: pmetricutiltest.NewExponentialHistograms("AB", "D", "EF", "GH"), + }, + { + name: "exponential_histogram/move_all_from_one_metric_in_each_scope", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, _ any) bool { + return m.Name() == "metricF" + }, + from: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewExponentialHistograms("AB", "CD", "E", "GH"), + expectTo: pmetricutiltest.NewExponentialHistograms("AB", "CD", "F", "GH"), + }, + { + name: "exponential_histogram/move_one", + moveIf: func(rl pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, m pmetric.Metric, dp any) bool { + rname, ok1 := rl.Resource().Attributes().Get("resourceName") + dpname, ok2 := dp.(pmetric.ExponentialHistogramDataPoint).Attributes().Get("dpName") + return ok1 && ok2 && rname.AsString() == "resourceA" && sl.Scope().Name() == "scopeD" && m.Name() == "metricF" && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewExponentialHistograms("A", "D", "F", "G"), + }, + { + name: "exponential_histogram/move_one_from_each_resource", + moveIf: func(_ pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, m pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.ExponentialHistogramDataPoint).Attributes().Get("dpName") + return ok && sl.Scope().Name() == "scopeD" && m.Name() == "metricE" && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewExponentialHistograms("AB", "D", "E", "G"), + }, + { + name: "exponential_histogram/move_one_from_each_scope", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.ExponentialHistogramDataPoint).Attributes().Get("dpName") + return ok && m.Name() == "metricE" && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewExponentialHistograms("AB", "CD", "E", "G"), + }, + { + name: "exponential_histogram/move_one_from_each_metric", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.ExponentialHistogramDataPoint).Attributes().Get("dpName") + return ok && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "H"), + expectTo: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "G"), + }, + { + name: "exponential_histogram/move_one_from_each_scope_in_one_resource", + moveIf: func(rl pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, _ any) bool { + rname, ok := rl.Resource().Attributes().Get("resourceName") + return ok && rname.AsString() == "resourceB" && m.Name() == "metricE" + }, + from: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.ExponentialHistogram("E", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("G"), pmetricutiltest.ExponentialHistogramDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewExponentialHistograms("B", "CD", "E", "GH"), + }, + { + name: "exponential_histogram/move_some_to_preexisting", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.ExponentialHistogramDataPoint).Attributes().Get("dpName") + return ok && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "GH"), + to: pmetricutiltest.NewExponentialHistograms("1", "2", "3", "4"), + expectFrom: pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "H"), + expectTo: func() pmetric.Metrics { + orig := pmetricutiltest.NewExponentialHistograms("1", "2", "3", "4") + extra := pmetricutiltest.NewExponentialHistograms("AB", "CD", "EF", "G") + extra.ResourceMetrics().MoveAndAppendTo(orig.ResourceMetrics()) + return orig + }(), + }, + + // summary + { + name: "summary/move_none", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + return false + }, + from: pmetricutiltest.NewSummaries("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewSummaries("AB", "CD", "EF", "GH"), + expectTo: pmetric.NewMetrics(), + }, + { + name: "summary/move_all", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + return true + }, + from: pmetricutiltest.NewSummaries("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetric.NewMetrics(), + expectTo: pmetricutiltest.NewSummaries("AB", "CD", "EF", "GH"), + }, + { + name: "summary/move_all_from_one_resource", + moveIf: func(rl pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + rname, ok := rl.Resource().Attributes().Get("resourceName") + return ok && rname.AsString() == "resourceB" + }, + from: pmetricutiltest.NewSummaries("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewSummaries("A", "CD", "EF", "GH"), + expectTo: pmetricutiltest.NewSummaries("B", "CD", "EF", "GH"), + }, + { + name: "summary/move_all_from_one_scope", + moveIf: func(rl pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + rname, ok := rl.Resource().Attributes().Get("resourceName") + return ok && rname.AsString() == "resourceB" && sl.Scope().Name() == "scopeC" + }, + from: pmetricutiltest.NewSummaries("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("D", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewSummaries("B", "C", "EF", "GH"), + }, + { + name: "summary/move_all_from_one_metric", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, _ any) bool { + return m.Name() == "metricE" + }, + from: pmetricutiltest.NewSummaries("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewSummaries("AB", "CD", "F", "GH"), + expectTo: pmetricutiltest.NewSummaries("AB", "CD", "E", "GH"), + }, + { + name: "summary/move_all_from_one_scope_in_each_resource", + moveIf: func(_ pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, _ pmetric.Metric, _ any) bool { + return sl.Scope().Name() == "scopeD" + }, + from: pmetricutiltest.NewSummaries("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewSummaries("AB", "C", "EF", "GH"), + expectTo: pmetricutiltest.NewSummaries("AB", "D", "EF", "GH"), + }, + { + name: "summary/move_all_from_one_metric_in_each_scope", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, _ any) bool { + return m.Name() == "metricF" + }, + from: pmetricutiltest.NewSummaries("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewSummaries("AB", "CD", "E", "GH"), + expectTo: pmetricutiltest.NewSummaries("AB", "CD", "F", "GH"), + }, + { + name: "summary/move_one", + moveIf: func(rl pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, m pmetric.Metric, dp any) bool { + rname, ok1 := rl.Resource().Attributes().Get("resourceName") + dpname, ok2 := dp.(pmetric.SummaryDataPoint).Attributes().Get("dpName") + return ok1 && ok2 && rname.AsString() == "resourceA" && sl.Scope().Name() == "scopeD" && m.Name() == "metricF" && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewSummaries("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewSummaries("A", "D", "F", "G"), + }, + { + name: "summary/move_one_from_each_resource", + moveIf: func(_ pmetric.ResourceMetrics, sl pmetric.ScopeMetrics, m pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.SummaryDataPoint).Attributes().Get("dpName") + return ok && sl.Scope().Name() == "scopeD" && m.Name() == "metricE" && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewSummaries("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewSummaries("AB", "D", "E", "G"), + }, + { + name: "summary/move_one_from_each_scope", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.SummaryDataPoint).Attributes().Get("dpName") + return ok && m.Name() == "metricE" && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewSummaries("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewSummaries("AB", "CD", "E", "G"), + }, + { + name: "summary/move_one_from_each_metric", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.SummaryDataPoint).Attributes().Get("dpName") + return ok && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewSummaries("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewSummaries("AB", "CD", "EF", "H"), + expectTo: pmetricutiltest.NewSummaries("AB", "CD", "EF", "G"), + }, + { + name: "summary/move_one_from_each_scope_in_one_resource", + moveIf: func(rl pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, m pmetric.Metric, _ any) bool { + rname, ok := rl.Resource().Attributes().Get("resourceName") + return ok && rname.AsString() == "resourceB" && m.Name() == "metricE" + }, + from: pmetricutiltest.NewSummaries("AB", "CD", "EF", "GH"), + to: pmetric.NewMetrics(), + expectFrom: pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("C", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Summary("E", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + ), + pmetricutiltest.Resource("B", + pmetricutiltest.Scope("C", + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + pmetricutiltest.Scope("D", + pmetricutiltest.Summary("F", pmetricutiltest.SummaryDataPoint("G"), pmetricutiltest.SummaryDataPoint("H")), + ), + ), + ), + expectTo: pmetricutiltest.NewSummaries("B", "CD", "E", "GH"), + }, + { + name: "summary/move_some_to_preexisting", + moveIf: func(_ pmetric.ResourceMetrics, _ pmetric.ScopeMetrics, _ pmetric.Metric, dp any) bool { + dpname, ok := dp.(pmetric.SummaryDataPoint).Attributes().Get("dpName") + return ok && dpname.AsString() == "dpG" + }, + from: pmetricutiltest.NewSummaries("AB", "CD", "EF", "GH"), + to: pmetricutiltest.NewSummaries("1", "2", "3", "4"), + expectFrom: pmetricutiltest.NewSummaries("AB", "CD", "EF", "H"), + expectTo: func() pmetric.Metrics { + orig := pmetricutiltest.NewSummaries("1", "2", "3", "4") + extra := pmetricutiltest.NewSummaries("AB", "CD", "EF", "G") + extra.ResourceMetrics().MoveAndAppendTo(orig.ResourceMetrics()) + return orig + }(), + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + pmetricutil.MoveDataPointsWithContextIf(tt.from, tt.to, tt.moveIf) + assert.NoError(t, pmetrictest.CompareMetrics(tt.expectFrom, tt.from), "from not modified as expected") + assert.NoError(t, pmetrictest.CompareMetrics(tt.expectTo, tt.to), "to not as expected") + }) + } +} diff --git a/connector/routingconnector/internal/pmetricutiltest/metrics.go b/connector/routingconnector/internal/pmetricutiltest/metrics.go index fb1902759e70..e041f53ecdd5 100644 --- a/connector/routingconnector/internal/pmetricutiltest/metrics.go +++ b/connector/routingconnector/internal/pmetricutiltest/metrics.go @@ -5,7 +5,7 @@ package pmetricutiltest // import "github.com/open-telemetry/opentelemetry-colle import "go.opentelemetry.io/collector/pdata/pmetric" -// NewMetrics returns a pmetric.Metrics with a uniform structure where resources, scopes, metrics, +// NewGauges returns a pmetric.Metrics with a uniform structure where resources, scopes, metrics, // and datapoints are identical across all instances, except for one identifying field. // // Identifying fields: @@ -14,7 +14,7 @@ import "go.opentelemetry.io/collector/pdata/pmetric" // - Metrics have a name with a value of "metricN" and a single time series of data points. // - DataPoints have an attribute "dpName" with a value of "dpN". // -// Example: NewMetrics("AB", "XYZ", "MN", "1234") returns: +// Example: NewGauges("AB", "XYZ", "MN", "1234") returns: // // resourceA, resourceB // each with scopeX, scopeY, scopeZ @@ -22,7 +22,7 @@ import "go.opentelemetry.io/collector/pdata/pmetric" // each with dp1, dp2, dp3, dp4 // // Each byte in the input string is a unique ID for the corresponding element. -func NewMetrics(resourceIDs, scopeIDs, metricIDs, dataPointIDs string) pmetric.Metrics { +func NewGauges(resourceIDs, scopeIDs, metricIDs, dataPointIDs string) pmetric.Metrics { md := pmetric.NewMetrics() for resourceN := 0; resourceN < len(resourceIDs); resourceN++ { rm := md.ResourceMetrics().AppendEmpty() @@ -44,6 +44,94 @@ func NewMetrics(resourceIDs, scopeIDs, metricIDs, dataPointIDs string) pmetric.M return md } +func NewSums(resourceIDs, scopeIDs, metricIDs, dataPointIDs string) pmetric.Metrics { + md := pmetric.NewMetrics() + for resourceN := 0; resourceN < len(resourceIDs); resourceN++ { + rm := md.ResourceMetrics().AppendEmpty() + rm.Resource().Attributes().PutStr("resourceName", "resource"+string(resourceIDs[resourceN])) + for scopeN := 0; scopeN < len(scopeIDs); scopeN++ { + sm := rm.ScopeMetrics().AppendEmpty() + sm.Scope().SetName("scope" + string(scopeIDs[scopeN])) + for metricN := 0; metricN < len(metricIDs); metricN++ { + m := sm.Metrics().AppendEmpty() + m.SetName("metric" + string(metricIDs[metricN])) + dps := m.SetEmptySum() + for dataPointN := 0; dataPointN < len(dataPointIDs); dataPointN++ { + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dp"+string(dataPointIDs[dataPointN])) + } + } + } + } + return md +} + +func NewHistograms(resourceIDs, scopeIDs, metricIDs, dataPointIDs string) pmetric.Metrics { + md := pmetric.NewMetrics() + for resourceN := 0; resourceN < len(resourceIDs); resourceN++ { + rm := md.ResourceMetrics().AppendEmpty() + rm.Resource().Attributes().PutStr("resourceName", "resource"+string(resourceIDs[resourceN])) + for scopeN := 0; scopeN < len(scopeIDs); scopeN++ { + sm := rm.ScopeMetrics().AppendEmpty() + sm.Scope().SetName("scope" + string(scopeIDs[scopeN])) + for metricN := 0; metricN < len(metricIDs); metricN++ { + m := sm.Metrics().AppendEmpty() + m.SetName("metric" + string(metricIDs[metricN])) + dps := m.SetEmptyHistogram() + for dataPointN := 0; dataPointN < len(dataPointIDs); dataPointN++ { + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dp"+string(dataPointIDs[dataPointN])) + } + } + } + } + return md +} + +func NewExponentialHistograms(resourceIDs, scopeIDs, metricIDs, dataPointIDs string) pmetric.Metrics { + md := pmetric.NewMetrics() + for resourceN := 0; resourceN < len(resourceIDs); resourceN++ { + rm := md.ResourceMetrics().AppendEmpty() + rm.Resource().Attributes().PutStr("resourceName", "resource"+string(resourceIDs[resourceN])) + for scopeN := 0; scopeN < len(scopeIDs); scopeN++ { + sm := rm.ScopeMetrics().AppendEmpty() + sm.Scope().SetName("scope" + string(scopeIDs[scopeN])) + for metricN := 0; metricN < len(metricIDs); metricN++ { + m := sm.Metrics().AppendEmpty() + m.SetName("metric" + string(metricIDs[metricN])) + dps := m.SetEmptyExponentialHistogram() + for dataPointN := 0; dataPointN < len(dataPointIDs); dataPointN++ { + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dp"+string(dataPointIDs[dataPointN])) + } + } + } + } + return md +} + +func NewSummaries(resourceIDs, scopeIDs, metricIDs, dataPointIDs string) pmetric.Metrics { + md := pmetric.NewMetrics() + for resourceN := 0; resourceN < len(resourceIDs); resourceN++ { + rm := md.ResourceMetrics().AppendEmpty() + rm.Resource().Attributes().PutStr("resourceName", "resource"+string(resourceIDs[resourceN])) + for scopeN := 0; scopeN < len(scopeIDs); scopeN++ { + sm := rm.ScopeMetrics().AppendEmpty() + sm.Scope().SetName("scope" + string(scopeIDs[scopeN])) + for metricN := 0; metricN < len(metricIDs); metricN++ { + m := sm.Metrics().AppendEmpty() + m.SetName("metric" + string(metricIDs[metricN])) + dps := m.SetEmptySummary() + for dataPointN := 0; dataPointN < len(dataPointIDs); dataPointN++ { + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dp"+string(dataPointIDs[dataPointN])) + } + } + } + } + return md +} + func NewMetricsFromOpts(resources ...pmetric.ResourceMetrics) pmetric.Metrics { md := pmetric.NewMetrics() for _, resource := range resources { @@ -70,7 +158,7 @@ func Scope(id string, metrics ...pmetric.Metric) pmetric.ScopeMetrics { return s } -func Metric(id string, dps ...pmetric.NumberDataPoint) pmetric.Metric { +func Gauge(id string, dps ...pmetric.NumberDataPoint) pmetric.Metric { m := pmetric.NewMetric() m.SetName("metric" + id) g := m.SetEmptyGauge() @@ -80,8 +168,66 @@ func Metric(id string, dps ...pmetric.NumberDataPoint) pmetric.Metric { return m } +func Sum(id string, dps ...pmetric.NumberDataPoint) pmetric.Metric { + m := pmetric.NewMetric() + m.SetName("metric" + id) + g := m.SetEmptySum() + for _, dp := range dps { + dp.CopyTo(g.DataPoints().AppendEmpty()) + } + return m +} + func NumberDataPoint(id string) pmetric.NumberDataPoint { dp := pmetric.NewNumberDataPoint() dp.Attributes().PutStr("dpName", "dp"+id) return dp } + +func Histogram(id string, dps ...pmetric.HistogramDataPoint) pmetric.Metric { + m := pmetric.NewMetric() + m.SetName("metric" + id) + g := m.SetEmptyHistogram() + for _, dp := range dps { + dp.CopyTo(g.DataPoints().AppendEmpty()) + } + return m +} + +func HistogramDataPoint(id string) pmetric.HistogramDataPoint { + dp := pmetric.NewHistogramDataPoint() + dp.Attributes().PutStr("dpName", "dp"+id) + return dp +} + +func ExponentialHistogram(id string, dps ...pmetric.ExponentialHistogramDataPoint) pmetric.Metric { + m := pmetric.NewMetric() + m.SetName("metric" + id) + g := m.SetEmptyExponentialHistogram() + for _, dp := range dps { + dp.CopyTo(g.DataPoints().AppendEmpty()) + } + return m +} + +func ExponentialHistogramDataPoint(id string) pmetric.ExponentialHistogramDataPoint { + dp := pmetric.NewExponentialHistogramDataPoint() + dp.Attributes().PutStr("dpName", "dp"+id) + return dp +} + +func Summary(id string, dps ...pmetric.SummaryDataPoint) pmetric.Metric { + m := pmetric.NewMetric() + m.SetName("metric" + id) + g := m.SetEmptySummary() + for _, dp := range dps { + dp.CopyTo(g.DataPoints().AppendEmpty()) + } + return m +} + +func SummaryDataPoint(id string) pmetric.SummaryDataPoint { + dp := pmetric.NewSummaryDataPoint() + dp.Attributes().PutStr("dpName", "dp"+id) + return dp +} diff --git a/connector/routingconnector/internal/pmetricutiltest/metrics_test.go b/connector/routingconnector/internal/pmetricutiltest/metrics_test.go index 9fcd2edebef6..47a73b5afc37 100644 --- a/connector/routingconnector/internal/pmetricutiltest/metrics_test.go +++ b/connector/routingconnector/internal/pmetricutiltest/metrics_test.go @@ -16,30 +16,120 @@ import ( func TestNewMetrics(t *testing.T) { t.Run("empty", func(t *testing.T) { expected := pmetric.NewMetrics() - assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetrics("", "", "", ""))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewGauges("", "", "", ""))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewSums("", "", "", ""))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewHistograms("", "", "", ""))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewExponentialHistograms("", "", "", ""))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewSummaries("", "", "", ""))) assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts())) }) t.Run("simple", func(t *testing.T) { - expected := func() pmetric.Metrics { - md := pmetric.NewMetrics() - r := md.ResourceMetrics().AppendEmpty() - r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA - s := r.ScopeMetrics().AppendEmpty() - s.Scope().SetName("scopeB") // resourceA.scopeB - m := s.Metrics().AppendEmpty() - m.SetName("metricC") // resourceA.scopeB.metricC - dps := m.SetEmptyGauge() - dp := dps.DataPoints().AppendEmpty() - dp.Attributes().PutStr("dpName", "dpD") // resourceA.scopeB.metricC.dpD - return md - }() - assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetrics("A", "B", "C", "D"))) - assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( - pmetricutiltest.Resource("A", - pmetricutiltest.Scope("B", pmetricutiltest.Metric("C", pmetricutiltest.NumberDataPoint("D"))), - ), - ))) + t.Run("gauge", func(t *testing.T) { + expected := func() pmetric.Metrics { + md := pmetric.NewMetrics() + r := md.ResourceMetrics().AppendEmpty() + r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA + s := r.ScopeMetrics().AppendEmpty() + s.Scope().SetName("scopeB") // resourceA.scopeB + m := s.Metrics().AppendEmpty() + m.SetName("metricC") // resourceA.scopeB.metricC + dps := m.SetEmptyGauge() + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpD") // resourceA.scopeB.metricC.dpD + return md + }() + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewGauges("A", "B", "C", "D"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("B", pmetricutiltest.Gauge("C", pmetricutiltest.NumberDataPoint("D"))), + ), + ))) + }) + t.Run("sum", func(t *testing.T) { + expected := func() pmetric.Metrics { + md := pmetric.NewMetrics() + r := md.ResourceMetrics().AppendEmpty() + r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA + s := r.ScopeMetrics().AppendEmpty() + s.Scope().SetName("scopeB") // resourceA.scopeB + m := s.Metrics().AppendEmpty() + m.SetName("metricC") // resourceA.scopeB.metricC + dps := m.SetEmptySum() + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpD") // resourceA.scopeB.metricC.dpD + return md + }() + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewSums("A", "B", "C", "D"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("B", pmetricutiltest.Sum("C", pmetricutiltest.NumberDataPoint("D"))), + ), + ))) + }) + t.Run("histogram", func(t *testing.T) { + expected := func() pmetric.Metrics { + md := pmetric.NewMetrics() + r := md.ResourceMetrics().AppendEmpty() + r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA + s := r.ScopeMetrics().AppendEmpty() + s.Scope().SetName("scopeB") // resourceA.scopeB + m := s.Metrics().AppendEmpty() + m.SetName("metricC") // resourceA.scopeB.metricC + dps := m.SetEmptyHistogram() + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpD") // resourceA.scopeB.metricC.dpD + return md + }() + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewHistograms("A", "B", "C", "D"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("B", pmetricutiltest.Histogram("C", pmetricutiltest.HistogramDataPoint("D"))), + ), + ))) + }) + t.Run("exponential_histogram", func(t *testing.T) { + expected := func() pmetric.Metrics { + md := pmetric.NewMetrics() + r := md.ResourceMetrics().AppendEmpty() + r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA + s := r.ScopeMetrics().AppendEmpty() + s.Scope().SetName("scopeB") // resourceA.scopeB + m := s.Metrics().AppendEmpty() + m.SetName("metricC") // resourceA.scopeB.metricC + dps := m.SetEmptyExponentialHistogram() + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpD") // resourceA.scopeB.metricC.dpD + return md + }() + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewExponentialHistograms("A", "B", "C", "D"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("B", pmetricutiltest.ExponentialHistogram("C", pmetricutiltest.ExponentialHistogramDataPoint("D"))), + ), + ))) + }) + t.Run("summary", func(t *testing.T) { + expected := func() pmetric.Metrics { + md := pmetric.NewMetrics() + r := md.ResourceMetrics().AppendEmpty() + r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA + s := r.ScopeMetrics().AppendEmpty() + s.Scope().SetName("scopeB") // resourceA.scopeB + m := s.Metrics().AppendEmpty() + m.SetName("metricC") // resourceA.scopeB.metricC + dps := m.SetEmptySummary() + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpD") // resourceA.scopeB.metricC.dpD + return md + }() + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewSummaries("A", "B", "C", "D"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("B", pmetricutiltest.Summary("C", pmetricutiltest.SummaryDataPoint("D"))), + ), + ))) + }) }) t.Run("two_resources", func(t *testing.T) { @@ -65,13 +155,13 @@ func TestNewMetrics(t *testing.T) { dp.Attributes().PutStr("dpName", "dpE") // resourceB.scopeC.metricD.dpE return md }() - assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetrics("AB", "C", "D", "E"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewGauges("AB", "C", "D", "E"))) assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( pmetricutiltest.Resource("A", - pmetricutiltest.Scope("C", pmetricutiltest.Metric("D", pmetricutiltest.NumberDataPoint("E"))), + pmetricutiltest.Scope("C", pmetricutiltest.Gauge("D", pmetricutiltest.NumberDataPoint("E"))), ), pmetricutiltest.Resource("B", - pmetricutiltest.Scope("C", pmetricutiltest.Metric("D", pmetricutiltest.NumberDataPoint("E"))), + pmetricutiltest.Scope("C", pmetricutiltest.Gauge("D", pmetricutiltest.NumberDataPoint("E"))), ), ))) }) @@ -97,65 +187,340 @@ func TestNewMetrics(t *testing.T) { dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeC.metricD.dpE return md }() - assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetrics("A", "BC", "D", "E"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewGauges("A", "BC", "D", "E"))) assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( pmetricutiltest.Resource("A", - pmetricutiltest.Scope("B", pmetricutiltest.Metric("D", pmetricutiltest.NumberDataPoint("E"))), - pmetricutiltest.Scope("C", pmetricutiltest.Metric("D", pmetricutiltest.NumberDataPoint("E"))), + pmetricutiltest.Scope("B", pmetricutiltest.Gauge("D", pmetricutiltest.NumberDataPoint("E"))), + pmetricutiltest.Scope("C", pmetricutiltest.Gauge("D", pmetricutiltest.NumberDataPoint("E"))), ), ))) }) t.Run("two_metrics", func(t *testing.T) { - expected := func() pmetric.Metrics { - md := pmetric.NewMetrics() - r := md.ResourceMetrics().AppendEmpty() - r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA - s := r.ScopeMetrics().AppendEmpty() - s.Scope().SetName("scopeB") // resourceA.scopeB - m := s.Metrics().AppendEmpty() - m.SetName("metricC") // resourceA.scopeB.metricC - dps := m.SetEmptyGauge() - dp := dps.DataPoints().AppendEmpty() - dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricC.dpE - m = s.Metrics().AppendEmpty() - m.SetName("metricD") // resourceA.scopeB.metricD - dps = m.SetEmptyGauge() - dp = dps.DataPoints().AppendEmpty() - dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricD.dpE - return md - }() - assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetrics("A", "B", "CD", "E"))) - assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( - pmetricutiltest.Resource("A", - pmetricutiltest.Scope("B", - pmetricutiltest.Metric("C", pmetricutiltest.NumberDataPoint("E")), - pmetricutiltest.Metric("D", pmetricutiltest.NumberDataPoint("E")), + t.Run("gauges", func(t *testing.T) { + expected := func() pmetric.Metrics { + md := pmetric.NewMetrics() + r := md.ResourceMetrics().AppendEmpty() + r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA + s := r.ScopeMetrics().AppendEmpty() + s.Scope().SetName("scopeB") // resourceA.scopeB + m := s.Metrics().AppendEmpty() + m.SetName("metricC") // resourceA.scopeB.metricC + dps := m.SetEmptyGauge() + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricC.dpE + m = s.Metrics().AppendEmpty() + m.SetName("metricD") // resourceA.scopeB.metricD + dps = m.SetEmptyGauge() + dp = dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricD.dpE + return md + }() + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewGauges("A", "B", "CD", "E"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("B", + pmetricutiltest.Gauge("C", pmetricutiltest.NumberDataPoint("E")), + pmetricutiltest.Gauge("D", pmetricutiltest.NumberDataPoint("E")), + ), ), - ), - ))) + ))) + }) + t.Run("sums", func(t *testing.T) { + expected := func() pmetric.Metrics { + md := pmetric.NewMetrics() + r := md.ResourceMetrics().AppendEmpty() + r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA + s := r.ScopeMetrics().AppendEmpty() + s.Scope().SetName("scopeB") // resourceA.scopeB + m := s.Metrics().AppendEmpty() + m.SetName("metricC") // resourceA.scopeB.metricC + dps := m.SetEmptySum() + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricC.dpE + m = s.Metrics().AppendEmpty() + m.SetName("metricD") // resourceA.scopeB.metricD + dps = m.SetEmptySum() + dp = dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricD.dpE + return md + }() + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewSums("A", "B", "CD", "E"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("B", + pmetricutiltest.Sum("C", pmetricutiltest.NumberDataPoint("E")), + pmetricutiltest.Sum("D", pmetricutiltest.NumberDataPoint("E")), + ), + ), + ))) + }) + t.Run("histograms", func(t *testing.T) { + expected := func() pmetric.Metrics { + md := pmetric.NewMetrics() + r := md.ResourceMetrics().AppendEmpty() + r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA + s := r.ScopeMetrics().AppendEmpty() + s.Scope().SetName("scopeB") // resourceA.scopeB + m := s.Metrics().AppendEmpty() + m.SetName("metricC") // resourceA.scopeB.metricC + dps := m.SetEmptyHistogram() + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricC.dpE + m = s.Metrics().AppendEmpty() + m.SetName("metricD") // resourceA.scopeB.metricD + dps = m.SetEmptyHistogram() + dp = dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricD.dpE + return md + }() + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewHistograms("A", "B", "CD", "E"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("B", + pmetricutiltest.Histogram("C", pmetricutiltest.HistogramDataPoint("E")), + pmetricutiltest.Histogram("D", pmetricutiltest.HistogramDataPoint("E")), + ), + ), + ))) + }) + t.Run("exponential_histograms", func(t *testing.T) { + expected := func() pmetric.Metrics { + md := pmetric.NewMetrics() + r := md.ResourceMetrics().AppendEmpty() + r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA + s := r.ScopeMetrics().AppendEmpty() + s.Scope().SetName("scopeB") // resourceA.scopeB + m := s.Metrics().AppendEmpty() + m.SetName("metricC") // resourceA.scopeB.metricC + dps := m.SetEmptyExponentialHistogram() + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricC.dpE + m = s.Metrics().AppendEmpty() + m.SetName("metricD") // resourceA.scopeB.metricD + dps = m.SetEmptyExponentialHistogram() + dp = dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricD.dpE + return md + }() + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewExponentialHistograms("A", "B", "CD", "E"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("B", + pmetricutiltest.ExponentialHistogram("C", pmetricutiltest.ExponentialHistogramDataPoint("E")), + pmetricutiltest.ExponentialHistogram("D", pmetricutiltest.ExponentialHistogramDataPoint("E")), + ), + ), + ))) + }) + t.Run("summaries", func(t *testing.T) { + expected := func() pmetric.Metrics { + md := pmetric.NewMetrics() + r := md.ResourceMetrics().AppendEmpty() + r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA + s := r.ScopeMetrics().AppendEmpty() + s.Scope().SetName("scopeB") // resourceA.scopeB + m := s.Metrics().AppendEmpty() + m.SetName("metricC") // resourceA.scopeB.metricC + dps := m.SetEmptySummary() + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricC.dpE + m = s.Metrics().AppendEmpty() + m.SetName("metricD") // resourceA.scopeB.metricD + dps = m.SetEmptySummary() + dp = dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricD.dpE + return md + }() + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewSummaries("A", "B", "CD", "E"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("B", + pmetricutiltest.Summary("C", pmetricutiltest.SummaryDataPoint("E")), + pmetricutiltest.Summary("D", pmetricutiltest.SummaryDataPoint("E")), + ), + ), + ))) + }) }) t.Run("two_datapoints", func(t *testing.T) { + t.Run("gauge", func(t *testing.T) { + expected := func() pmetric.Metrics { + md := pmetric.NewMetrics() + r := md.ResourceMetrics().AppendEmpty() + r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA + s := r.ScopeMetrics().AppendEmpty() + s.Scope().SetName("scopeB") // resourceA.scopeB + m := s.Metrics().AppendEmpty() + m.SetName("metricC") // resourceA.scopeB.metricC + dps := m.SetEmptyGauge() + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpD") // resourceA.scopeB.metricC.dpD + dp = dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricC.dpE + return md + }() + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewGauges("A", "B", "C", "DE"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("B", pmetricutiltest.Gauge("C", pmetricutiltest.NumberDataPoint("D"), pmetricutiltest.NumberDataPoint("E"))), + ), + ))) + }) + t.Run("sum", func(t *testing.T) { + expected := func() pmetric.Metrics { + md := pmetric.NewMetrics() + r := md.ResourceMetrics().AppendEmpty() + r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA + s := r.ScopeMetrics().AppendEmpty() + s.Scope().SetName("scopeB") // resourceA.scopeB + m := s.Metrics().AppendEmpty() + m.SetName("metricC") // resourceA.scopeB.metricC + dps := m.SetEmptySum() + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpD") // resourceA.scopeB.metricC.dpD + dp = dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricC.dpE + return md + }() + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewSums("A", "B", "C", "DE"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("B", pmetricutiltest.Sum("C", pmetricutiltest.NumberDataPoint("D"), pmetricutiltest.NumberDataPoint("E"))), + ), + ))) + }) + t.Run("histogram", func(t *testing.T) { + expected := func() pmetric.Metrics { + md := pmetric.NewMetrics() + r := md.ResourceMetrics().AppendEmpty() + r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA + s := r.ScopeMetrics().AppendEmpty() + s.Scope().SetName("scopeB") // resourceA.scopeB + m := s.Metrics().AppendEmpty() + m.SetName("metricC") // resourceA.scopeB.metricC + dps := m.SetEmptyHistogram() + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpD") // resourceA.scopeB.metricC.dpD + dp = dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricC.dpE + return md + }() + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewHistograms("A", "B", "C", "DE"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("B", pmetricutiltest.Histogram("C", pmetricutiltest.HistogramDataPoint("D"), pmetricutiltest.HistogramDataPoint("E"))), + ), + ))) + }) + t.Run("exponential_histogram", func(t *testing.T) { + expected := func() pmetric.Metrics { + md := pmetric.NewMetrics() + r := md.ResourceMetrics().AppendEmpty() + r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA + s := r.ScopeMetrics().AppendEmpty() + s.Scope().SetName("scopeB") // resourceA.scopeB + m := s.Metrics().AppendEmpty() + m.SetName("metricC") // resourceA.scopeB.metricC + dps := m.SetEmptyExponentialHistogram() + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpD") // resourceA.scopeB.metricC.dpD + dp = dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricC.dpE + return md + }() + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewExponentialHistograms("A", "B", "C", "DE"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("B", pmetricutiltest.ExponentialHistogram("C", pmetricutiltest.ExponentialHistogramDataPoint("D"), pmetricutiltest.ExponentialHistogramDataPoint("E"))), + ), + ))) + }) + t.Run("summary", func(t *testing.T) { + expected := func() pmetric.Metrics { + md := pmetric.NewMetrics() + r := md.ResourceMetrics().AppendEmpty() + r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA + s := r.ScopeMetrics().AppendEmpty() + s.Scope().SetName("scopeB") // resourceA.scopeB + m := s.Metrics().AppendEmpty() + m.SetName("metricC") // resourceA.scopeB.metricC + dps := m.SetEmptySummary() + dp := dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpD") // resourceA.scopeB.metricC.dpD + dp = dps.DataPoints().AppendEmpty() + dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricC.dpE + return md + }() + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewSummaries("A", "B", "C", "DE"))) + assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( + pmetricutiltest.Resource("A", + pmetricutiltest.Scope("B", pmetricutiltest.Summary("C", pmetricutiltest.SummaryDataPoint("D"), pmetricutiltest.SummaryDataPoint("E"))), + ), + ))) + }) + }) + + t.Run("all_metric_types", func(t *testing.T) { expected := func() pmetric.Metrics { md := pmetric.NewMetrics() r := md.ResourceMetrics().AppendEmpty() r.Resource().Attributes().PutStr("resourceName", "resourceA") // resourceA s := r.ScopeMetrics().AppendEmpty() s.Scope().SetName("scopeB") // resourceA.scopeB + m := s.Metrics().AppendEmpty() m.SetName("metricC") // resourceA.scopeB.metricC - dps := m.SetEmptyGauge() - dp := dps.DataPoints().AppendEmpty() - dp.Attributes().PutStr("dpName", "dpD") // resourceA.scopeB.metricC.dpD - dp = dps.DataPoints().AppendEmpty() - dp.Attributes().PutStr("dpName", "dpE") // resourceA.scopeB.metricC.dpE + gauge := m.SetEmptyGauge() + ndp := gauge.DataPoints().AppendEmpty() + ndp.Attributes().PutStr("dpName", "dpX") // resourceA.scopeB.metricC.dpX + ndp = gauge.DataPoints().AppendEmpty() + ndp.Attributes().PutStr("dpName", "dpY") // resourceA.scopeB.metricC.dpY + + m = s.Metrics().AppendEmpty() + m.SetName("metricD") // resourceA.scopeB.metricD + sum := m.SetEmptySum() + ndp = sum.DataPoints().AppendEmpty() + ndp.Attributes().PutStr("dpName", "dpX") // resourceA.scopeB.metricD.dpX + ndp = sum.DataPoints().AppendEmpty() + ndp.Attributes().PutStr("dpName", "dpY") // resourceA.scopeB.metricD.dpY + + m = s.Metrics().AppendEmpty() + m.SetName("metricE") // resourceA.scopeB.metricE + hist := m.SetEmptyHistogram() + hdp := hist.DataPoints().AppendEmpty() + hdp.Attributes().PutStr("dpName", "dpX") // resourceA.scopeB.metricE.dpX + hdp = hist.DataPoints().AppendEmpty() + hdp.Attributes().PutStr("dpName", "dpY") // resourceA.scopeB.metricE.dpY + + m = s.Metrics().AppendEmpty() + m.SetName("metricF") // resourceA.scopeB.metricF + expHist := m.SetEmptyExponentialHistogram() + edp := expHist.DataPoints().AppendEmpty() + edp.Attributes().PutStr("dpName", "dpX") // resourceA.scopeB.metricF.dpX + edp = expHist.DataPoints().AppendEmpty() + edp.Attributes().PutStr("dpName", "dpY") // resourceA.scopeB.metricF.dpY + + m = s.Metrics().AppendEmpty() + m.SetName("metricG") // resourceA.scopeB.metricG + smry := m.SetEmptySummary() + sdp := smry.DataPoints().AppendEmpty() + sdp.Attributes().PutStr("dpName", "dpX") // resourceA.scopeB.metricG.dpX + sdp = smry.DataPoints().AppendEmpty() + sdp.Attributes().PutStr("dpName", "dpY") // resourceA.scopeB.metricG.dpY + return md }() - assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetrics("A", "B", "C", "DE"))) assert.NoError(t, pmetrictest.CompareMetrics(expected, pmetricutiltest.NewMetricsFromOpts( pmetricutiltest.Resource("A", - pmetricutiltest.Scope("B", pmetricutiltest.Metric("C", pmetricutiltest.NumberDataPoint("D"), pmetricutiltest.NumberDataPoint("E"))), + pmetricutiltest.Scope("B", + pmetricutiltest.Gauge("C", pmetricutiltest.NumberDataPoint("X"), pmetricutiltest.NumberDataPoint("Y")), + pmetricutiltest.Sum("D", pmetricutiltest.NumberDataPoint("X"), pmetricutiltest.NumberDataPoint("Y")), + pmetricutiltest.Histogram("E", pmetricutiltest.HistogramDataPoint("X"), pmetricutiltest.HistogramDataPoint("Y")), + pmetricutiltest.ExponentialHistogram("F", pmetricutiltest.ExponentialHistogramDataPoint("X"), pmetricutiltest.ExponentialHistogramDataPoint("Y")), + pmetricutiltest.Summary("G", pmetricutiltest.SummaryDataPoint("X"), pmetricutiltest.SummaryDataPoint("Y")), + ), ), ))) }) diff --git a/connector/routingconnector/metrics.go b/connector/routingconnector/metrics.go index 7bdc81519b4b..92bd654caa47 100644 --- a/connector/routingconnector/metrics.go +++ b/connector/routingconnector/metrics.go @@ -15,6 +15,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/connector/routingconnector/internal/pmetricutil" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottldatapoint" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlmetric" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlresource" ) @@ -97,6 +98,15 @@ func (c *metricsConnector) switchMetrics(ctx context.Context, md pmetric.Metrics return isMatch }, ) + case "datapoint": + pmetricutil.MoveDataPointsWithContextIf(md, matchedMetrics, + func(rm pmetric.ResourceMetrics, sm pmetric.ScopeMetrics, m pmetric.Metric, dp any) bool { + dptx := ottldatapoint.NewTransformContext(dp, m, sm.Metrics(), sm.Scope(), rm.Resource(), sm, rm) + _, isMatch, err := route.dataPointStatement.Execute(ctx, dptx) + errs = errors.Join(errs, err) + return isMatch + }, + ) } if errs != nil { if c.config.ErrorMode == ottl.PropagateError { diff --git a/connector/routingconnector/metrics_test.go b/connector/routingconnector/metrics_test.go index fbbf7b383381..2f8335980940 100644 --- a/connector/routingconnector/metrics_test.go +++ b/connector/routingconnector/metrics_test.go @@ -515,9 +515,13 @@ func TestMetricsConnectorDetailed(t *testing.T) { isMetricX := `name == "metricX"` isMetricY := `name == "metricY"` - isScopeCFromLowerContext := `instrumentation_scope.name == "scopeC"` - isScopeDFromLowerContext := `instrumentation_scope.name == "scopeD"` + isDataPointG := `attributes["dpName"] == "dpG"` + isDataPointH := `attributes["dpName"] == "dpH"` + isDataPointX := `attributes["dpName"] == "dpX"` + isDataPointY := `attributes["dpName"] == "dpY"` + isMetricFFromLowerContext := `metric.name == "metricF"` + isScopeDFromLowerContext := `instrumentation_scope.name == "scopeD"` isResourceBFromLowerContext := `resource.attributes["resourceName"] == "resourceB"` testCases := []struct { @@ -536,10 +540,10 @@ func TestMetricsConnectorDetailed(t *testing.T) { withDefault(idSinkD), ), ctx: context.Background(), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink0: pmetric.Metrics{}, expectSink1: pmetric.Metrics{}, - expectSinkD: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + expectSinkD: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), }, { name: "request/match_any_value", @@ -554,8 +558,8 @@ func TestMetricsConnectorDetailed(t *testing.T) { ), map[string]string{"X-Tenant": "notacme"}, ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink1: pmetric.Metrics{}, expectSinkD: pmetric.Metrics{}, }, @@ -566,8 +570,8 @@ func TestMetricsConnectorDetailed(t *testing.T) { withDefault(idSinkD), ), ctx: withGRPCMetadata(context.Background(), map[string]string{"X-Tenant": "acme"}), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink1: pmetric.Metrics{}, expectSinkD: pmetric.Metrics{}, }, @@ -578,10 +582,10 @@ func TestMetricsConnectorDetailed(t *testing.T) { withDefault(idSinkD), ), ctx: withGRPCMetadata(context.Background(), map[string]string{"X-Tenant": "notacme"}), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink0: pmetric.Metrics{}, expectSink1: pmetric.Metrics{}, - expectSinkD: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + expectSinkD: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), }, { name: "request/match_http_value", @@ -590,8 +594,8 @@ func TestMetricsConnectorDetailed(t *testing.T) { withDefault(idSinkD), ), ctx: withHTTPMetadata(context.Background(), map[string][]string{"X-Tenant": {"acme"}}), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink1: pmetric.Metrics{}, expectSinkD: pmetric.Metrics{}, }, @@ -602,8 +606,8 @@ func TestMetricsConnectorDetailed(t *testing.T) { withDefault(idSinkD), ), ctx: withHTTPMetadata(context.Background(), map[string][]string{"X-Tenant": {"notacme", "acme"}}), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink1: pmetric.Metrics{}, expectSinkD: pmetric.Metrics{}, }, @@ -614,10 +618,10 @@ func TestMetricsConnectorDetailed(t *testing.T) { withDefault(idSinkD), ), ctx: withHTTPMetadata(context.Background(), map[string][]string{"X-Tenant": {"notacme"}}), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink0: pmetric.Metrics{}, expectSink1: pmetric.Metrics{}, - expectSinkD: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + expectSinkD: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), }, { name: "resource/all_match_first_only", @@ -626,8 +630,8 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("resource", isResourceY, idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink1: pmetric.Metrics{}, expectSinkD: pmetric.Metrics{}, }, @@ -638,9 +642,9 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("resource", "true", idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink0: pmetric.Metrics{}, - expectSink1: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + expectSink1: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSinkD: pmetric.Metrics{}, }, { @@ -650,8 +654,8 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("resource", isResourceA+" or "+isResourceB, idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink1: pmetric.Metrics{}, expectSinkD: pmetric.Metrics{}, }, @@ -662,9 +666,9 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("resource", isResourceB, idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("A", "CD", "EF", "GH"), - expectSink1: pmetricutiltest.NewMetrics("B", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("A", "CD", "EF", "GH"), + expectSink1: pmetricutiltest.NewGauges("B", "CD", "EF", "GH"), expectSinkD: pmetric.Metrics{}, }, { @@ -674,10 +678,10 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("resource", isResourceB, idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink0: pmetric.Metrics{}, - expectSink1: pmetricutiltest.NewMetrics("B", "CD", "EF", "GH"), - expectSinkD: pmetricutiltest.NewMetrics("A", "CD", "EF", "GH"), + expectSink1: pmetricutiltest.NewGauges("B", "CD", "EF", "GH"), + expectSinkD: pmetricutiltest.NewGauges("A", "CD", "EF", "GH"), }, { name: "resource/some_match_without_default", @@ -685,9 +689,9 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("resource", isResourceX, idSink0), withRoute("resource", isResourceB, idSink1), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink0: pmetric.Metrics{}, - expectSink1: pmetricutiltest.NewMetrics("B", "CD", "EF", "GH"), + expectSink1: pmetricutiltest.NewGauges("B", "CD", "EF", "GH"), expectSinkD: pmetric.Metrics{}, }, { @@ -697,10 +701,10 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("resource", isResourceY, idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink0: pmetric.Metrics{}, expectSink1: pmetric.Metrics{}, - expectSinkD: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + expectSinkD: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), }, { name: "resource/match_none_without_default", @@ -708,7 +712,7 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("resource", isResourceX, idSink0), withRoute("resource", isResourceY, idSink1), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink0: pmetric.Metrics{}, expectSink1: pmetric.Metrics{}, expectSinkD: pmetric.Metrics{}, @@ -720,8 +724,8 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("metric", isMetricY, idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink1: pmetric.Metrics{}, expectSinkD: pmetric.Metrics{}, }, @@ -732,9 +736,9 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("metric", "true", idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink0: pmetric.Metrics{}, - expectSink1: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + expectSink1: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSinkD: pmetric.Metrics{}, }, { @@ -744,8 +748,8 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("metric", isMetricE+" or "+isMetricF, idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink1: pmetric.Metrics{}, expectSinkD: pmetric.Metrics{}, }, @@ -756,9 +760,9 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("metric", isMetricF, idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("AB", "CD", "E", "GH"), - expectSink1: pmetricutiltest.NewMetrics("AB", "CD", "F", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "E", "GH"), + expectSink1: pmetricutiltest.NewGauges("AB", "CD", "F", "GH"), expectSinkD: pmetric.Metrics{}, }, { @@ -768,10 +772,10 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("metric", isMetricF, idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink0: pmetric.Metrics{}, - expectSink1: pmetricutiltest.NewMetrics("AB", "CD", "F", "GH"), - expectSinkD: pmetricutiltest.NewMetrics("AB", "CD", "E", "GH"), + expectSink1: pmetricutiltest.NewGauges("AB", "CD", "F", "GH"), + expectSinkD: pmetricutiltest.NewGauges("AB", "CD", "E", "GH"), }, { name: "metric/some_match_without_default", @@ -779,9 +783,9 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("metric", isMetricX, idSink0), withRoute("metric", isMetricF, idSink1), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink0: pmetric.Metrics{}, - expectSink1: pmetricutiltest.NewMetrics("AB", "CD", "F", "GH"), + expectSink1: pmetricutiltest.NewGauges("AB", "CD", "F", "GH"), expectSinkD: pmetric.Metrics{}, }, { @@ -791,10 +795,10 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("metric", isMetricY, idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink0: pmetric.Metrics{}, expectSink1: pmetric.Metrics{}, - expectSinkD: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + expectSinkD: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), }, { name: "metric/match_none_without_default", @@ -802,7 +806,7 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("metric", isMetricX, idSink0), withRoute("metric", isMetricY, idSink1), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), expectSink0: pmetric.Metrics{}, expectSink1: pmetric.Metrics{}, expectSinkD: pmetric.Metrics{}, @@ -814,22 +818,22 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("metric", isMetricY, idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("B", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("B", "CD", "EF", "GH"), expectSink1: pmetric.Metrics{}, - expectSinkD: pmetricutiltest.NewMetrics("A", "CD", "EF", "GH"), + expectSinkD: pmetricutiltest.NewGauges("A", "CD", "EF", "GH"), }, { name: "metric/with_scope_condition", cfg: testConfig( - withRoute("metric", isScopeCFromLowerContext, idSink0), + withRoute("metric", isScopeDFromLowerContext, idSink0), withRoute("metric", isMetricY, idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("AB", "C", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "D", "EF", "GH"), expectSink1: pmetric.Metrics{}, - expectSinkD: pmetricutiltest.NewMetrics("AB", "D", "EF", "GH"), + expectSinkD: pmetricutiltest.NewGauges("AB", "C", "EF", "GH"), }, { name: "metric/with_resource_and_scope_conditions", @@ -838,28 +842,158 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("metric", isMetricY, idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("B", "D", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("B", "D", "EF", "GH"), expectSink1: pmetric.Metrics{}, expectSinkD: pmetricutiltest.NewMetricsFromOpts( pmetricutiltest.Resource("A", pmetricutiltest.Scope("C", - pmetricutiltest.Metric("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), - pmetricutiltest.Metric("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), ), pmetricutiltest.Scope("D", - pmetricutiltest.Metric("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), - pmetricutiltest.Metric("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), ), ), pmetricutiltest.Resource("B", pmetricutiltest.Scope("C", - pmetricutiltest.Metric("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), - pmetricutiltest.Metric("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("E", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), + pmetricutiltest.Gauge("F", pmetricutiltest.NumberDataPoint("G"), pmetricutiltest.NumberDataPoint("H")), ), ), ), }, + { + name: "datapoint/all_match_first_only", + cfg: testConfig( + withRoute("datapoint", "true", idSink0), + withRoute("datapoint", isDataPointY, idSink1), + withDefault(idSinkD), + ), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink1: pmetric.Metrics{}, + expectSinkD: pmetric.Metrics{}, + }, + { + name: "datapoint/all_match_last_only", + cfg: testConfig( + withRoute("datapoint", isDataPointX, idSink0), + withRoute("datapoint", "true", idSink1), + withDefault(idSinkD), + ), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetric.Metrics{}, + expectSink1: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSinkD: pmetric.Metrics{}, + }, + { + name: "datapoint/all_match_only_once", + cfg: testConfig( + withRoute("datapoint", "true", idSink0), + withRoute("datapoint", isDataPointG+" or "+isDataPointH, idSink1), + withDefault(idSinkD), + ), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink1: pmetric.Metrics{}, + expectSinkD: pmetric.Metrics{}, + }, + { + name: "datapoint/each_matches_one", + cfg: testConfig( + withRoute("datapoint", isDataPointG, idSink0), + withRoute("datapoint", isDataPointH, idSink1), + withDefault(idSinkD), + ), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "EF", "G"), + expectSink1: pmetricutiltest.NewGauges("AB", "CD", "EF", "H"), + expectSinkD: pmetric.Metrics{}, + }, + { + name: "datapoint/some_match_with_default", + cfg: testConfig( + withRoute("datapoint", isDataPointX, idSink0), + withRoute("datapoint", isDataPointH, idSink1), + withDefault(idSinkD), + ), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetric.Metrics{}, + expectSink1: pmetricutiltest.NewGauges("AB", "CD", "EF", "H"), + expectSinkD: pmetricutiltest.NewGauges("AB", "CD", "EF", "G"), + }, + { + name: "datapoint/some_match_without_default", + cfg: testConfig( + withRoute("datapoint", isDataPointX, idSink0), + withRoute("datapoint", isDataPointH, idSink1), + ), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetric.Metrics{}, + expectSink1: pmetricutiltest.NewGauges("AB", "CD", "EF", "H"), + expectSinkD: pmetric.Metrics{}, + }, + { + name: "datapoint/match_none_with_default", + cfg: testConfig( + withRoute("datapoint", isDataPointX, idSink0), + withRoute("datapoint", isDataPointY, idSink1), + withDefault(idSinkD), + ), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetric.Metrics{}, + expectSink1: pmetric.Metrics{}, + expectSinkD: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + }, + { + name: "datapoint/match_none_without_default", + cfg: testConfig( + withRoute("datapoint", isDataPointX, idSink0), + withRoute("datapoint", isDataPointY, idSink1), + ), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetric.Metrics{}, + expectSink1: pmetric.Metrics{}, + expectSinkD: pmetric.Metrics{}, + }, + { + name: "datapoint/with_resource_condition", + cfg: testConfig( + withRoute("datapoint", isResourceBFromLowerContext, idSink0), + withRoute("datapoint", isDataPointY, idSink1), + withDefault(idSinkD), + ), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("B", "CD", "EF", "GH"), + expectSink1: pmetric.Metrics{}, + expectSinkD: pmetricutiltest.NewGauges("A", "CD", "EF", "GH"), + }, + { + name: "datapoint/with_scope_condition", + cfg: testConfig( + withRoute("datapoint", isScopeDFromLowerContext, idSink0), + withRoute("datapoint", isDataPointY, idSink1), + withDefault(idSinkD), + ), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "D", "EF", "GH"), + expectSink1: pmetric.Metrics{}, + expectSinkD: pmetricutiltest.NewGauges("AB", "C", "EF", "GH"), + }, + { + name: "datapoint/with_metric_condition", + cfg: testConfig( + withRoute("datapoint", isMetricFFromLowerContext, idSink0), + withRoute("datapoint", isDataPointY, idSink1), + withDefault(idSinkD), + ), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "F", "GH"), + expectSink1: pmetric.Metrics{}, + expectSinkD: pmetricutiltest.NewGauges("AB", "CD", "E", "GH"), + }, { name: "mixed/match_resource_then_metrics", cfg: testConfig( @@ -867,10 +1001,10 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("metric", isMetricE, idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("A", "CD", "EF", "GH"), - expectSink1: pmetricutiltest.NewMetrics("B", "CD", "E", "GH"), - expectSinkD: pmetricutiltest.NewMetrics("B", "CD", "F", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("A", "CD", "EF", "GH"), + expectSink1: pmetricutiltest.NewGauges("B", "CD", "E", "GH"), + expectSinkD: pmetricutiltest.NewGauges("B", "CD", "F", "GH"), }, { name: "mixed/match_metrics_then_resource", @@ -879,10 +1013,58 @@ func TestMetricsConnectorDetailed(t *testing.T) { withRoute("resource", isResourceB, idSink1), withDefault(idSinkD), ), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("AB", "CD", "E", "GH"), - expectSink1: pmetricutiltest.NewMetrics("B", "CD", "F", "GH"), - expectSinkD: pmetricutiltest.NewMetrics("A", "CD", "F", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "E", "GH"), + expectSink1: pmetricutiltest.NewGauges("B", "CD", "F", "GH"), + expectSinkD: pmetricutiltest.NewGauges("A", "CD", "F", "GH"), + }, + { + name: "mixed/match_resource_then_datapoint", + cfg: testConfig( + withRoute("resource", isResourceA, idSink0), + withRoute("datapoint", isDataPointG, idSink1), + withDefault(idSinkD), + ), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("A", "CD", "EF", "GH"), + expectSink1: pmetricutiltest.NewGauges("B", "CD", "EF", "G"), + expectSinkD: pmetricutiltest.NewGauges("B", "CD", "EF", "H"), + }, + { + name: "mixed/match_datapoint_then_resource", + cfg: testConfig( + withRoute("datapoint", isDataPointG, idSink0), + withRoute("resource", isResourceB, idSink1), + withDefault(idSinkD), + ), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "EF", "G"), + expectSink1: pmetricutiltest.NewGauges("B", "CD", "EF", "H"), + expectSinkD: pmetricutiltest.NewGauges("A", "CD", "EF", "H"), + }, + { + name: "mixed/match_metric_then_datapoint", + cfg: testConfig( + withRoute("metric", isMetricE, idSink0), + withRoute("datapoint", isDataPointG, idSink1), + withDefault(idSinkD), + ), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "E", "GH"), + expectSink1: pmetricutiltest.NewGauges("AB", "CD", "F", "G"), + expectSinkD: pmetricutiltest.NewGauges("AB", "CD", "F", "H"), + }, + { + name: "mixed/match_datapoint_then_metric", + cfg: testConfig( + withRoute("datapoint", isDataPointG, idSink0), + withRoute("metric", isMetricE, idSink1), + withDefault(idSinkD), + ), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "EF", "G"), + expectSink1: pmetricutiltest.NewGauges("AB", "CD", "E", "H"), + expectSinkD: pmetricutiltest.NewGauges("AB", "CD", "F", "H"), }, { name: "mixed/match_resource_then_grpc_request", @@ -892,9 +1074,9 @@ func TestMetricsConnectorDetailed(t *testing.T) { withDefault(idSinkD), ), ctx: withGRPCMetadata(context.Background(), map[string]string{"X-Tenant": "acme"}), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("A", "CD", "EF", "GH"), - expectSink1: pmetricutiltest.NewMetrics("B", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("A", "CD", "EF", "GH"), + expectSink1: pmetricutiltest.NewGauges("B", "CD", "EF", "GH"), expectSinkD: pmetric.Metrics{}, }, { @@ -905,9 +1087,22 @@ func TestMetricsConnectorDetailed(t *testing.T) { withDefault(idSinkD), ), ctx: withGRPCMetadata(context.Background(), map[string]string{"X-Tenant": "acme"}), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("AB", "CD", "F", "GH"), - expectSink1: pmetricutiltest.NewMetrics("AB", "CD", "E", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "F", "GH"), + expectSink1: pmetricutiltest.NewGauges("AB", "CD", "E", "GH"), + expectSinkD: pmetric.Metrics{}, + }, + { + name: "mixed/match_datapoint_then_grpc_request", + cfg: testConfig( + withRoute("datapoint", isDataPointG, idSink0), + withRoute("request", isAcme, idSink1), + withDefault(idSinkD), + ), + ctx: withGRPCMetadata(context.Background(), map[string]string{"X-Tenant": "acme"}), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "EF", "G"), + expectSink1: pmetricutiltest.NewGauges("AB", "CD", "EF", "H"), expectSinkD: pmetric.Metrics{}, }, { @@ -918,9 +1113,9 @@ func TestMetricsConnectorDetailed(t *testing.T) { withDefault(idSinkD), ), ctx: withHTTPMetadata(context.Background(), map[string][]string{"X-Tenant": {"acme"}}), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("A", "CD", "EF", "GH"), - expectSink1: pmetricutiltest.NewMetrics("B", "CD", "EF", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("A", "CD", "EF", "GH"), + expectSink1: pmetricutiltest.NewGauges("B", "CD", "EF", "GH"), expectSinkD: pmetric.Metrics{}, }, { @@ -931,9 +1126,22 @@ func TestMetricsConnectorDetailed(t *testing.T) { withDefault(idSinkD), ), ctx: withHTTPMetadata(context.Background(), map[string][]string{"X-Tenant": {"acme"}}), - input: pmetricutiltest.NewMetrics("AB", "CD", "EF", "GH"), - expectSink0: pmetricutiltest.NewMetrics("AB", "CD", "F", "GH"), - expectSink1: pmetricutiltest.NewMetrics("AB", "CD", "E", "GH"), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "F", "GH"), + expectSink1: pmetricutiltest.NewGauges("AB", "CD", "E", "GH"), + expectSinkD: pmetric.Metrics{}, + }, + { + name: "mixed/match_datapoint_then_http_request", + cfg: testConfig( + withRoute("datapoint", isDataPointG, idSink0), + withRoute("request", isAcme, idSink1), + withDefault(idSinkD), + ), + ctx: withHTTPMetadata(context.Background(), map[string][]string{"X-Tenant": {"acme"}}), + input: pmetricutiltest.NewGauges("AB", "CD", "EF", "GH"), + expectSink0: pmetricutiltest.NewGauges("AB", "CD", "EF", "G"), + expectSink1: pmetricutiltest.NewGauges("AB", "CD", "EF", "H"), expectSinkD: pmetric.Metrics{}, }, } diff --git a/connector/routingconnector/router.go b/connector/routingconnector/router.go index 98f05bc92287..665bc59fa821 100644 --- a/connector/routingconnector/router.go +++ b/connector/routingconnector/router.go @@ -14,6 +14,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/connector/routingconnector/internal/common" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottldatapoint" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottllog" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlmetric" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlresource" @@ -31,11 +32,12 @@ type consumerProvider[C any] func(...pipeline.ID) (C, error) // parameter C is expected to be one of: consumer.Traces, consumer.Metrics, or // consumer.Logs. type router[C any] struct { - logger *zap.Logger - resourceParser ottl.Parser[ottlresource.TransformContext] - spanParser ottl.Parser[ottlspan.TransformContext] - metricParser ottl.Parser[ottlmetric.TransformContext] - logParser ottl.Parser[ottllog.TransformContext] + logger *zap.Logger + resourceParser ottl.Parser[ottlresource.TransformContext] + spanParser ottl.Parser[ottlspan.TransformContext] + metricParser ottl.Parser[ottlmetric.TransformContext] + dataPointParser ottl.Parser[ottldatapoint.TransformContext] + logParser ottl.Parser[ottllog.TransformContext] table []RoutingTableItem routes map[string]routingItem[C] @@ -72,17 +74,18 @@ func newRouter[C any]( } type routingItem[C any] struct { - consumer C - statementContext string - requestCondition *requestCondition - resourceStatement *ottl.Statement[ottlresource.TransformContext] - spanStatement *ottl.Statement[ottlspan.TransformContext] - metricStatement *ottl.Statement[ottlmetric.TransformContext] - logStatement *ottl.Statement[ottllog.TransformContext] + consumer C + statementContext string + requestCondition *requestCondition + resourceStatement *ottl.Statement[ottlresource.TransformContext] + spanStatement *ottl.Statement[ottlspan.TransformContext] + metricStatement *ottl.Statement[ottlmetric.TransformContext] + dataPointStatement *ottl.Statement[ottldatapoint.TransformContext] + logStatement *ottl.Statement[ottllog.TransformContext] } func (r *router[C]) buildParsers(table []RoutingTableItem, settings component.TelemetrySettings) error { - var buildResource, buildSpan, buildMetric, buildLog bool + var buildResource, buildSpan, buildMetric, buildDataPoint, buildLog bool for _, item := range table { switch item.Context { case "", "resource": @@ -91,6 +94,8 @@ func (r *router[C]) buildParsers(table []RoutingTableItem, settings component.Te buildSpan = true case "metric": buildMetric = true + case "datapoint": + buildDataPoint = true case "log": buildLog = true } @@ -126,6 +131,19 @@ func (r *router[C]) buildParsers(table []RoutingTableItem, settings component.Te ) if err == nil { r.metricParser = parser + } else { + errs = errors.Join(errs, err) + } + } + if buildDataPoint { + parser, err := ottldatapoint.NewParser( + common.Functions[ottldatapoint.TransformContext](), + settings, + ) + if err == nil { + r.dataPointParser = parser + } else { + errs = errors.Join(errs, err) } } if buildLog { @@ -216,6 +234,12 @@ func (r *router[C]) registerRouteConsumers() (err error) { return err } route.metricStatement = statement + case "datapoint": + statement, err := r.dataPointParser.ParseStatement(item.Statement) + if err != nil { + return err + } + route.dataPointStatement = statement case "log": statement, err := r.logParser.ParseStatement(item.Statement) if err != nil {