Skip to content

Commit

Permalink
[pkg/ottl] Changed replacement string (replace_all* functions) to be …
Browse files Browse the repository at this point in the history
…a path expression to a string telemetry field or a literal string
  • Loading branch information
rnishtala-sumo committed Jun 9, 2023
1 parent 44ceeb8 commit c4418a4
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 83 deletions.
9 changes: 7 additions & 2 deletions .chloggen/ottl_function_changes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@ change_type: enhancement
component: pkg/ottl

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Changed replacement_pattern (replacement) string to be a path expression to a string telemetry field or a literal string
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:
subtext: |
The following replacement functions now accept a path expression as a replacement:
- replace_match
- replace_pattern
- replace_all_matches
- replace_all_patterns
4 changes: 2 additions & 2 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 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 c4418a4

Please sign in to comment.