Skip to content

Commit b247914

Browse files
[pkg/ottl] Changed replacement string to be a path expression to a string telemetry field or a literal string (open-telemetry#23210)
* [pkg/ottl] Changed replacement string to be a path expression to a string telemetry field or a literal string * [pkg/ottl] Changed replacement string (replace_all* functions) to be a path expression to a string telemetry field or a literal string
1 parent 3b62a17 commit b247914

10 files changed

+290
-123
lines changed

.chloggen/ottl_function_changes.yaml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Use this changelog template to create an entry for release notes.
2+
# If your change doesn't affect end users, such as a test fix or a tooling change,
3+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
4+
5+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
6+
change_type: enhancement
7+
8+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
9+
component: pkg/ottl
10+
11+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
12+
note: Change replacement functions to accept a path expression as a replacement
13+
14+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
15+
issues: [22787]
16+
17+
# (Optional) One or more lines of additional information to render under the primary note.
18+
# These lines will be padded with 2 spaces and then inserted directly into the document.
19+
# Use pipe (|) for multiline entries.
20+
subtext: |
21+
The following replacement functions now accept a path expression as a replacement:
22+
- replace_match
23+
- replace_pattern
24+
- replace_all_matches
25+
- replace_all_patterns

pkg/ottl/ottlfuncs/README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ Examples:
148148

149149
The `replace_all_matches` function replaces any matching string value with the replacement string.
150150

151-
`target` is a path expression to a `pdata.Map` type field. `pattern` is a string following [filepath.Match syntax](https://pkg.go.dev/path/filepath#Match). `replacement` is a string.
151+
`target` is a path expression to a `pdata.Map` type field. `pattern` is a string following [filepath.Match syntax](https://pkg.go.dev/path/filepath#Match). `replacement` is either a path expression to a string telemetry field or a literal string.
152152

153153
Each string value in `target` that matches `pattern` will get replaced with `replacement`. Non-string values are ignored.
154154

@@ -162,7 +162,7 @@ Examples:
162162

163163
The `replace_all_patterns` function replaces any segments in a string value or key that match the regex pattern with the replacement string.
164164

165-
`target` is a path expression to a `pdata.Map` type field. `regex` is a regex string indicating a segment to replace. `replacement` is a string.
165+
`target` is a path expression to a `pdata.Map` type field. `regex` is a regex string indicating a segment to replace. `replacement` is either a path expression to a string telemetry field or a literal string.
166166

167167
`mode` determines whether the match and replace will occur on the map's value or key. Valid values are `key` and `value`.
168168

@@ -186,7 +186,7 @@ If using OTTL outside of collector configuration, `$` should not be escaped and
186186

187187
The `replace_match` function allows replacing entire strings if they match a glob pattern.
188188

189-
`target` is a path expression to a telemetry field. `pattern` is a string following [filepath.Match syntax](https://pkg.go.dev/path/filepath#Match). `replacement` is a string.
189+
`target` is a path expression to a telemetry field. `pattern` is a string following [filepath.Match syntax](https://pkg.go.dev/path/filepath#Match). `replacement` is either a path expression to a string telemetry field or a literal string.
190190

191191
If `target` matches `pattern` it will get replaced with `replacement`.
192192

@@ -200,7 +200,7 @@ Examples:
200200

201201
The `replace_pattern` function allows replacing all string sections that match a regex pattern with a new value.
202202

203-
`target` is a path expression to a telemetry field. `regex` is a regex string indicating a segment to replace. `replacement` is a string.
203+
`target` is a path expression to a telemetry field. `regex` is a regex string indicating a segment to replace. `replacement` is either a path expression to a string telemetry field or a literal string.
204204

205205
If one or more sections of `target` match `regex` they will get replaced with `replacement`.
206206

pkg/ottl/ottlfuncs/func_replace_all_matches.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ import (
1414
)
1515

1616
type ReplaceAllMatchesArguments[K any] struct {
17-
Target ottl.PMapGetter[K] `ottlarg:"0"`
18-
Pattern string `ottlarg:"1"`
19-
Replacement string `ottlarg:"2"`
17+
Target ottl.PMapGetter[K] `ottlarg:"0"`
18+
Pattern string `ottlarg:"1"`
19+
Replacement ottl.StringGetter[K] `ottlarg:"2"`
2020
}
2121

2222
func NewReplaceAllMatchesFactory[K any]() ottl.Factory[K] {
@@ -33,7 +33,7 @@ func createReplaceAllMatchesFunction[K any](_ ottl.FunctionContext, oArgs ottl.A
3333
return replaceAllMatches(args.Target, args.Pattern, args.Replacement)
3434
}
3535

36-
func replaceAllMatches[K any](target ottl.PMapGetter[K], pattern string, replacement string) (ottl.ExprFunc[K], error) {
36+
func replaceAllMatches[K any](target ottl.PMapGetter[K], pattern string, replacement ottl.StringGetter[K]) (ottl.ExprFunc[K], error) {
3737
glob, err := glob.Compile(pattern)
3838
if err != nil {
3939
return nil, fmt.Errorf("the pattern supplied to replace_match is not a valid pattern: %w", err)
@@ -43,9 +43,13 @@ func replaceAllMatches[K any](target ottl.PMapGetter[K], pattern string, replace
4343
if err != nil {
4444
return nil, err
4545
}
46+
replacementVal, err := replacement.Get(ctx, tCtx)
47+
if err != nil {
48+
return nil, err
49+
}
4650
val.Range(func(key string, value pcommon.Value) bool {
4751
if glob.Match(value.Str()) {
48-
value.SetStr(replacement)
52+
value.SetStr(replacementVal)
4953
}
5054
return true
5155
})

pkg/ottl/ottlfuncs/func_replace_all_matches_test.go

+29-11
Original file line numberDiff line numberDiff line change
@@ -29,25 +29,33 @@ func Test_replaceAllMatches(t *testing.T) {
2929
name string
3030
target ottl.PMapGetter[pcommon.Map]
3131
pattern string
32-
replacement string
32+
replacement ottl.StringGetter[pcommon.Map]
3333
want func(pcommon.Map)
3434
}{
3535
{
36-
name: "replace only matches",
37-
target: target,
38-
pattern: "hello*",
39-
replacement: "hello {universe}",
36+
name: "replace only matches",
37+
target: target,
38+
pattern: "hello*",
39+
replacement: ottl.StandardStringGetter[pcommon.Map]{
40+
Getter: func(context.Context, pcommon.Map) (interface{}, error) {
41+
return "hello {universe}", nil
42+
},
43+
},
4044
want: func(expectedMap pcommon.Map) {
4145
expectedMap.PutStr("test", "hello {universe}")
4246
expectedMap.PutStr("test2", "hello {universe}")
4347
expectedMap.PutStr("test3", "goodbye")
4448
},
4549
},
4650
{
47-
name: "no matches",
48-
target: target,
49-
pattern: "nothing*",
50-
replacement: "nothing {matches}",
51+
name: "no matches",
52+
target: target,
53+
pattern: "nothing*",
54+
replacement: ottl.StandardStringGetter[pcommon.Map]{
55+
Getter: func(context.Context, pcommon.Map) (interface{}, error) {
56+
return "nothing {matches}", nil
57+
},
58+
},
5159
want: func(expectedMap pcommon.Map) {
5260
expectedMap.PutStr("test", "hello world")
5361
expectedMap.PutStr("test2", "hello")
@@ -82,8 +90,13 @@ func Test_replaceAllMatches_bad_input(t *testing.T) {
8290
return tCtx, nil
8391
},
8492
}
93+
replacement := &ottl.StandardStringGetter[interface{}]{
94+
Getter: func(context.Context, interface{}) (interface{}, error) {
95+
return "{replacement}", nil
96+
},
97+
}
8598

86-
exprFunc, err := replaceAllMatches[interface{}](target, "*", "{replacement}")
99+
exprFunc, err := replaceAllMatches[interface{}](target, "*", replacement)
87100
assert.NoError(t, err)
88101
_, err = exprFunc(nil, input)
89102
assert.Error(t, err)
@@ -95,8 +108,13 @@ func Test_replaceAllMatches_get_nil(t *testing.T) {
95108
return tCtx, nil
96109
},
97110
}
111+
replacement := &ottl.StandardStringGetter[interface{}]{
112+
Getter: func(context.Context, interface{}) (interface{}, error) {
113+
return "{anything}", nil
114+
},
115+
}
98116

99-
exprFunc, err := replaceAllMatches[interface{}](target, "*", "{anything}")
117+
exprFunc, err := replaceAllMatches[interface{}](target, "*", replacement)
100118
assert.NoError(t, err)
101119
_, err = exprFunc(nil, nil)
102120
assert.Error(t, err)

pkg/ottl/ottlfuncs/func_replace_all_patterns.go

+11-7
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ const (
1919
)
2020

2121
type ReplaceAllPatternsArguments[K any] struct {
22-
Target ottl.PMapGetter[K] `ottlarg:"0"`
23-
Mode string `ottlarg:"1"`
24-
RegexPattern string `ottlarg:"2"`
25-
Replacement string `ottlarg:"3"`
22+
Target ottl.PMapGetter[K] `ottlarg:"0"`
23+
Mode string `ottlarg:"1"`
24+
RegexPattern string `ottlarg:"2"`
25+
Replacement ottl.StringGetter[K] `ottlarg:"3"`
2626
}
2727

2828
func NewReplaceAllPatternsFactory[K any]() ottl.Factory[K] {
@@ -39,7 +39,7 @@ func createReplaceAllPatternsFunction[K any](_ ottl.FunctionContext, oArgs ottl.
3939
return replaceAllPatterns(args.Target, args.Mode, args.RegexPattern, args.Replacement)
4040
}
4141

42-
func replaceAllPatterns[K any](target ottl.PMapGetter[K], mode string, regexPattern string, replacement string) (ottl.ExprFunc[K], error) {
42+
func replaceAllPatterns[K any](target ottl.PMapGetter[K], mode string, regexPattern string, replacement ottl.StringGetter[K]) (ottl.ExprFunc[K], error) {
4343
compiledPattern, err := regexp.Compile(regexPattern)
4444
if err != nil {
4545
return nil, fmt.Errorf("the regex pattern supplied to replace_all_patterns is not a valid pattern: %w", err)
@@ -53,20 +53,24 @@ func replaceAllPatterns[K any](target ottl.PMapGetter[K], mode string, regexPatt
5353
if err != nil {
5454
return nil, err
5555
}
56+
replacementVal, err := replacement.Get(ctx, tCtx)
57+
if err != nil {
58+
return nil, err
59+
}
5660
updated := pcommon.NewMap()
5761
updated.EnsureCapacity(val.Len())
5862
val.Range(func(key string, originalValue pcommon.Value) bool {
5963
switch mode {
6064
case modeValue:
6165
if compiledPattern.MatchString(originalValue.Str()) {
62-
updatedString := compiledPattern.ReplaceAllString(originalValue.Str(), replacement)
66+
updatedString := compiledPattern.ReplaceAllString(originalValue.Str(), replacementVal)
6367
updated.PutStr(key, updatedString)
6468
} else {
6569
originalValue.CopyTo(updated.PutEmpty(key))
6670
}
6771
case modeKey:
6872
if compiledPattern.MatchString(key) {
69-
updatedKey := compiledPattern.ReplaceAllString(key, replacement)
73+
updatedKey := compiledPattern.ReplaceAllString(key, replacementVal)
7074
originalValue.CopyTo(updated.PutEmpty(updatedKey))
7175
} else {
7276
originalValue.CopyTo(updated.PutEmpty(key))

0 commit comments

Comments
 (0)