Skip to content

Commit cb3accd

Browse files
committed
Add drop_bucket function
Signed-off-by: Israel Blancas <[email protected]>
1 parent 1ed907e commit cb3accd

File tree

10 files changed

+709
-1
lines changed

10 files changed

+709
-1
lines changed

.chloggen/40280.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: transformprocessor
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add support to drop_bucket OTTL function.
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [40280]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: [user]

processor/transformprocessor/CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ New functions must update the appropriate registry. For common functions, updat
1212

1313
Unit tests must be added for all new functions. Unit test files must start with `func_` and end in `_test`. Unit tests must be placed in the same directory as the function. Functions that are not specific to a pipeline should be tested independently of any specific pipeline. Functions that are specific to a pipeline should be tests against that pipeline.
1414

15-
All new functions should have integration tests added to any usable pipeline's `processing_test.go` tests. The purpose of these tests is not to test the function's logic, but its ability to be used within a specific pipeline.
15+
All new functions should have integration tests added to any usable pipeline's `processor_tests.go` tests. The purpose of these tests is not to test the function's logic, but its ability to be used within a specific pipeline.
1616

1717
## New Values
1818

processor/transformprocessor/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ In addition to the common OTTL functions, the processor defines its own function
261261
- [aggregate_on_attributes](#aggregate_on_attributes)
262262
- [convert_exponential_histogram_to_histogram](#convert_exponential_histogram_to_histogram)
263263
- [aggregate_on_attribute_value](#aggregate_on_attribute_value)
264+
- [drop_bucket](#drop_bucket)
264265

265266
### convert_sum_to_gauge
266267

@@ -582,6 +583,19 @@ statements:
582583

583584
To aggregate only using a specified set of attributes, you can use `keep_matching_keys`.
584585

586+
### drop_bucket
587+
588+
`drop_bucket(pattern)`
589+
590+
The `drop_bucket` function removes histogram buckets whose bounds match the provided regex pattern.
591+
592+
`pattern` is a string containing a valid regular expression to match against bucket bounds.
593+
594+
Examples:
595+
596+
- `drop_bucket("^10$") where metric.name == "http_request_duration"` - Remove the bucket with bound exactly equal to 10
597+
- `drop_bucket("^(5|20)$") where metric.name == "request_size"` - Remove buckets with bounds 5 and 20
598+
- `drop_bucket("^1.*") where metric.name == "latency"` - Remove all buckets with bounds starting with 1
585599

586600
## Examples
587601

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package metrics // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor/internal/metrics"
5+
6+
import (
7+
"context"
8+
"errors"
9+
"fmt"
10+
"regexp"
11+
"strconv"
12+
13+
"go.opentelemetry.io/collector/pdata/pmetric"
14+
15+
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
16+
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlmetric"
17+
)
18+
19+
type DropBucketArguments struct {
20+
Pattern string
21+
}
22+
23+
func newDropBucketFactory() ottl.Factory[ottlmetric.TransformContext] {
24+
return ottl.NewFactory(
25+
"drop_bucket",
26+
&DropBucketArguments{},
27+
createDropBucketFunction,
28+
)
29+
}
30+
31+
func createDropBucketFunction(_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[ottlmetric.TransformContext], error) {
32+
args, ok := oArgs.(*DropBucketArguments)
33+
34+
if !ok {
35+
return nil, errors.New("DropBucketFactory args must be of type *DropBucketArguments[K]")
36+
}
37+
38+
return dropBucketFunc(args.Pattern), nil
39+
}
40+
41+
func dropBucketFunc(pattern string) ottl.ExprFunc[ottlmetric.TransformContext] {
42+
return func(_ context.Context, tCtx ottlmetric.TransformContext) (any, error) {
43+
metric := tCtx.GetMetric()
44+
if metric.Type() != pmetric.MetricTypeHistogram {
45+
return nil, nil
46+
}
47+
48+
compiledPattern, err := regexp.Compile(pattern)
49+
if err != nil {
50+
return nil, fmt.Errorf("the regex pattern supplied to drop_bucket is not a valid pattern: %w", err)
51+
}
52+
53+
dps := metric.Histogram().DataPoints()
54+
for i := 0; i < dps.Len(); i++ {
55+
hdp := dps.At(i)
56+
bounds := hdp.ExplicitBounds()
57+
counts := hdp.BucketCounts()
58+
59+
boundsSlice := bounds.AsRaw()
60+
countsSlice := counts.AsRaw()
61+
62+
countsToRemove := make(map[int]bool)
63+
idx := 1
64+
65+
newBounds := RemoveIfFloat64(boundsSlice, func(bound float64, _ int) bool {
66+
defer func() {
67+
idx++
68+
}()
69+
if compiledPattern.MatchString(strconv.FormatFloat(bound, 'f', -1, 64)) {
70+
countsToRemove[idx] = true
71+
return true
72+
}
73+
74+
return false
75+
})
76+
77+
if len(countsToRemove) == 0 {
78+
continue
79+
}
80+
81+
count := uint64(0)
82+
newCounts := RemoveIfUint64(countsSlice, func(c uint64, idx int) bool {
83+
if countsToRemove[idx] {
84+
return true
85+
}
86+
count += c
87+
return false
88+
})
89+
90+
hdp.ExplicitBounds().FromRaw(newBounds)
91+
hdp.BucketCounts().FromRaw(newCounts)
92+
hdp.SetCount(count)
93+
94+
// Remove sum since it would be incorrect after removing buckets
95+
hdp.RemoveSum()
96+
}
97+
98+
return nil, nil
99+
}
100+
}

0 commit comments

Comments
 (0)