diff --git a/pkg/config/metricsconfig.go b/pkg/config/metricsconfig.go index edab03c32e..361f777b09 100644 --- a/pkg/config/metricsconfig.go +++ b/pkg/config/metricsconfig.go @@ -1,6 +1,7 @@ package config import ( + "maps" "slices" "sync" "time" @@ -77,30 +78,44 @@ func (mcd *metricsConfig) GetBucketBoundaries() []float64 { func (mcd *metricsConfig) BuildMeterProviderViews() []sdkmetric.View { mcd.mux.RLock() defer mcd.mux.RUnlock() - var views []sdkmetric.View - for key, value := range mcd.metricsExposure { - if *value.Enabled { - views = append(views, sdkmetric.NewView( - sdkmetric.Instrument{Name: key}, - sdkmetric.Stream{ - AttributeFilter: func(kv attribute.KeyValue) bool { - return !slices.Contains(value.DisabledLabelDimensions, string(kv.Key)) - }, - Aggregation: sdkmetric.AggregationExplicitBucketHistogram{ - Boundaries: value.BucketBoundaries, - NoMinMax: false, - }, - }, - )) - } else if !*value.Enabled { - views = append(views, sdkmetric.NewView( - sdkmetric.Instrument{Name: key}, - sdkmetric.Stream{ - Aggregation: sdkmetric.AggregationDrop{}, - }, - )) - } + + views := []sdkmetric.View{} + + if len(mcd.metricsExposure) > 0 { + metricsExposure := maps.Clone(mcd.metricsExposure) + views = append(views, func(i sdkmetric.Instrument) (sdkmetric.Stream, bool) { + s := sdkmetric.Stream{Name: i.Name, Description: i.Description, Unit: i.Unit} + + config, exists := metricsExposure[i.Name] + if !exists { + return s, false + } + + if config.Enabled != nil && !*config.Enabled { + s.Aggregation = sdkmetric.AggregationDrop{} + return s, true + } + + if len(config.DisabledLabelDimensions) > 0 { + s.AttributeFilter = func(kv attribute.KeyValue) bool { + return !slices.Contains(config.DisabledLabelDimensions, string(kv.Key)) + } + } + + if len(config.BucketBoundaries) > 0 { + aggregation := sdkmetric.DefaultAggregationSelector(i.Kind) + switch a := aggregation.(type) { + case sdkmetric.AggregationExplicitBucketHistogram: + a.Boundaries = config.BucketBoundaries + a.NoMinMax = false + s.Aggregation = a + } + } + + return s, true + }) } + return views } diff --git a/pkg/config/metricsconfig_test.go b/pkg/config/metricsconfig_test.go index 7fa66d7d88..b2078db79a 100644 --- a/pkg/config/metricsconfig_test.go +++ b/pkg/config/metricsconfig_test.go @@ -105,13 +105,39 @@ func Test_metricsConfig_BuildMeterProviderViews(t *testing.T) { expectedSize: 0, }, { - name: "Case 2: metrics enabled", + name: "Case 2: there is no matching entry on the exposure config", metricsExposure: map[string]metricExposureConfig{ "metric1": {Enabled: boolPtr(true), DisabledLabelDimensions: []string{"dim1"}, BucketBoundaries: []float64{0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 15, 20, 25, 30}}, }, expectedSize: 1, + validateFunc: func(views []sdkmetric.View) bool { + stream, _ := views[0](sdkmetric.Instrument{Name: "metric2"}) + assert := stream.AttributeFilter == nil + assert = assert && stream.Aggregation == nil + return assert + }, + }, + { + name: "Case 3: metrics enabled, no transformation configured", + metricsExposure: map[string]metricExposureConfig{ + "metric1": {Enabled: boolPtr(true)}, + }, + expectedSize: 1, validateFunc: func(views []sdkmetric.View) bool { stream, _ := views[0](sdkmetric.Instrument{Name: "metric1"}) + assert := stream.AttributeFilter == nil + assert = assert && stream.Aggregation == nil + return assert + }, + }, + { + name: "Case 4: metrics enabled, histogram metric", + metricsExposure: map[string]metricExposureConfig{ + "metric1": {Enabled: boolPtr(true), DisabledLabelDimensions: []string{"dim1"}, BucketBoundaries: []float64{0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 15, 20, 25, 30}}, + }, + expectedSize: 1, + validateFunc: func(views []sdkmetric.View) bool { + stream, _ := views[0](sdkmetric.Instrument{Name: "metric1", Kind: sdkmetric.InstrumentKindHistogram}) assert := stream.AttributeFilter(attribute.String("policy_validation_mode", "")) assert = assert && !stream.AttributeFilter(attribute.String("dim1", "")) assert = assert && reflect.DeepEqual(stream.Aggregation, sdkmetric.AggregationExplicitBucketHistogram{ @@ -122,7 +148,21 @@ func Test_metricsConfig_BuildMeterProviderViews(t *testing.T) { }, }, { - name: "Case 3: metrics disabled", + name: "Case 5: metrics enabled, non histogram metric", + metricsExposure: map[string]metricExposureConfig{ + "metric1": {Enabled: boolPtr(true), DisabledLabelDimensions: []string{"dim1"}, BucketBoundaries: []float64{0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 15, 20, 25, 30}}, + }, + expectedSize: 1, + validateFunc: func(views []sdkmetric.View) bool { + stream, _ := views[0](sdkmetric.Instrument{Name: "metric1", Kind: sdkmetric.InstrumentKindCounter}) + assert := stream.AttributeFilter(attribute.String("policy_validation_mode", "")) + assert = assert && !stream.AttributeFilter(attribute.String("dim1", "")) + assert = assert && stream.Aggregation == nil + return assert + }, + }, + { + name: "Case 6: metrics disabled", metricsExposure: map[string]metricExposureConfig{ "metric1": {Enabled: boolPtr(false)}, },