Skip to content

Commit

Permalink
[pkg/ottl] Changed replacement string to be a path expression to a st…
Browse files Browse the repository at this point in the history
…ring 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
  • Loading branch information
rnishtala-sumo committed Jun 12, 2023
1 parent 3b62a17 commit b247914
Show file tree
Hide file tree
Showing 10 changed files with 290 additions and 123 deletions.
25 changes: 25 additions & 0 deletions .chloggen/ottl_function_changes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Use this changelog template to create an entry for release notes.
# If your change doesn't affect end users, such as a test fix or a tooling change,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: pkg/ottl

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Change replacement functions to accept a path expression as a replacement

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [22787]

# (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: |
The following replacement functions now accept a path expression as a replacement:
- replace_match
- replace_pattern
- replace_all_matches
- replace_all_patterns
8 changes: 4 additions & 4 deletions pkg/ottl/ottlfuncs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ Examples:

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

`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.
`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.

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

Expand All @@ -162,7 +162,7 @@ Examples:

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

`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.
`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.

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

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

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

`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.
`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.

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

Expand All @@ -200,7 +200,7 @@ Examples:

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

`target` is a path expression to a telemetry field. `regex` is a regex string indicating a segment to replace. `replacement` is a string.
`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.

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

Expand Down
14 changes: 9 additions & 5 deletions pkg/ottl/ottlfuncs/func_replace_all_matches.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import (
)

type ReplaceAllMatchesArguments[K any] struct {
Target ottl.PMapGetter[K] `ottlarg:"0"`
Pattern string `ottlarg:"1"`
Replacement string `ottlarg:"2"`
Target ottl.PMapGetter[K] `ottlarg:"0"`
Pattern string `ottlarg:"1"`
Replacement ottl.StringGetter[K] `ottlarg:"2"`
}

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

func replaceAllMatches[K any](target ottl.PMapGetter[K], pattern string, replacement string) (ottl.ExprFunc[K], error) {
func replaceAllMatches[K any](target ottl.PMapGetter[K], pattern string, replacement ottl.StringGetter[K]) (ottl.ExprFunc[K], error) {
glob, err := glob.Compile(pattern)
if err != nil {
return nil, fmt.Errorf("the pattern supplied to replace_match is not a valid pattern: %w", err)
Expand All @@ -43,9 +43,13 @@ func replaceAllMatches[K any](target ottl.PMapGetter[K], pattern string, replace
if err != nil {
return nil, err
}
replacementVal, err := replacement.Get(ctx, tCtx)
if err != nil {
return nil, err
}
val.Range(func(key string, value pcommon.Value) bool {
if glob.Match(value.Str()) {
value.SetStr(replacement)
value.SetStr(replacementVal)
}
return true
})
Expand Down
40 changes: 29 additions & 11 deletions pkg/ottl/ottlfuncs/func_replace_all_matches_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,33 @@ func Test_replaceAllMatches(t *testing.T) {
name string
target ottl.PMapGetter[pcommon.Map]
pattern string
replacement string
replacement ottl.StringGetter[pcommon.Map]
want func(pcommon.Map)
}{
{
name: "replace only matches",
target: target,
pattern: "hello*",
replacement: "hello {universe}",
name: "replace only matches",
target: target,
pattern: "hello*",
replacement: ottl.StandardStringGetter[pcommon.Map]{
Getter: func(context.Context, pcommon.Map) (interface{}, error) {
return "hello {universe}", nil
},
},
want: func(expectedMap pcommon.Map) {
expectedMap.PutStr("test", "hello {universe}")
expectedMap.PutStr("test2", "hello {universe}")
expectedMap.PutStr("test3", "goodbye")
},
},
{
name: "no matches",
target: target,
pattern: "nothing*",
replacement: "nothing {matches}",
name: "no matches",
target: target,
pattern: "nothing*",
replacement: ottl.StandardStringGetter[pcommon.Map]{
Getter: func(context.Context, pcommon.Map) (interface{}, error) {
return "nothing {matches}", nil
},
},
want: func(expectedMap pcommon.Map) {
expectedMap.PutStr("test", "hello world")
expectedMap.PutStr("test2", "hello")
Expand Down Expand Up @@ -82,8 +90,13 @@ func Test_replaceAllMatches_bad_input(t *testing.T) {
return tCtx, nil
},
}
replacement := &ottl.StandardStringGetter[interface{}]{
Getter: func(context.Context, interface{}) (interface{}, error) {
return "{replacement}", nil
},
}

exprFunc, err := replaceAllMatches[interface{}](target, "*", "{replacement}")
exprFunc, err := replaceAllMatches[interface{}](target, "*", replacement)
assert.NoError(t, err)
_, err = exprFunc(nil, input)
assert.Error(t, err)
Expand All @@ -95,8 +108,13 @@ func Test_replaceAllMatches_get_nil(t *testing.T) {
return tCtx, nil
},
}
replacement := &ottl.StandardStringGetter[interface{}]{
Getter: func(context.Context, interface{}) (interface{}, error) {
return "{anything}", nil
},
}

exprFunc, err := replaceAllMatches[interface{}](target, "*", "{anything}")
exprFunc, err := replaceAllMatches[interface{}](target, "*", replacement)
assert.NoError(t, err)
_, err = exprFunc(nil, nil)
assert.Error(t, err)
Expand Down
18 changes: 11 additions & 7 deletions pkg/ottl/ottlfuncs/func_replace_all_patterns.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ const (
)

type ReplaceAllPatternsArguments[K any] struct {
Target ottl.PMapGetter[K] `ottlarg:"0"`
Mode string `ottlarg:"1"`
RegexPattern string `ottlarg:"2"`
Replacement string `ottlarg:"3"`
Target ottl.PMapGetter[K] `ottlarg:"0"`
Mode string `ottlarg:"1"`
RegexPattern string `ottlarg:"2"`
Replacement ottl.StringGetter[K] `ottlarg:"3"`
}

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

func replaceAllPatterns[K any](target ottl.PMapGetter[K], mode string, regexPattern string, replacement string) (ottl.ExprFunc[K], error) {
func replaceAllPatterns[K any](target ottl.PMapGetter[K], mode string, regexPattern string, replacement ottl.StringGetter[K]) (ottl.ExprFunc[K], error) {
compiledPattern, err := regexp.Compile(regexPattern)
if err != nil {
return nil, fmt.Errorf("the regex pattern supplied to replace_all_patterns is not a valid pattern: %w", err)
Expand All @@ -53,20 +53,24 @@ func replaceAllPatterns[K any](target ottl.PMapGetter[K], mode string, regexPatt
if err != nil {
return nil, err
}
replacementVal, err := replacement.Get(ctx, tCtx)
if err != nil {
return nil, err
}
updated := pcommon.NewMap()
updated.EnsureCapacity(val.Len())
val.Range(func(key string, originalValue pcommon.Value) bool {
switch mode {
case modeValue:
if compiledPattern.MatchString(originalValue.Str()) {
updatedString := compiledPattern.ReplaceAllString(originalValue.Str(), replacement)
updatedString := compiledPattern.ReplaceAllString(originalValue.Str(), replacementVal)
updated.PutStr(key, updatedString)
} else {
originalValue.CopyTo(updated.PutEmpty(key))
}
case modeKey:
if compiledPattern.MatchString(key) {
updatedKey := compiledPattern.ReplaceAllString(key, replacement)
updatedKey := compiledPattern.ReplaceAllString(key, replacementVal)
originalValue.CopyTo(updated.PutEmpty(updatedKey))
} else {
originalValue.CopyTo(updated.PutEmpty(key))
Expand Down
Loading

0 comments on commit b247914

Please sign in to comment.