Skip to content

Commit

Permalink
[pkg/ottl] Update IsMatch to convert bool int and float to strings (o…
Browse files Browse the repository at this point in the history
…pen-telemetry#16503)

Updates IsMatch to intelligently convert bools, ints, and floats to strings before matching with the regex. This helps with IsMatch and attributes usage.

Co-authored-by: Evan Bradley <[email protected]>
Co-authored-by: Bogdan Drutu <[email protected]>
  • Loading branch information
3 people authored and shalper2 committed Dec 6, 2022
1 parent f6ad8d8 commit 855c243
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 15 deletions.
16 changes: 16 additions & 0 deletions .chloggen/ottl-improve-ismatch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# 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: Updates the IsMatch function to convert bools, ints, and floats to strings before matching.

# One or more tracking issues related to the change
issues: [16503]

# (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:
2 changes: 1 addition & 1 deletion pkg/ottl/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/alecthomas/participle/v2 v2.0.0-beta.5
github.com/gobwas/glob v0.2.3
github.com/iancoleman/strcase v0.2.0
github.com/json-iterator/go v1.1.12
github.com/stretchr/testify v1.8.1
go.opentelemetry.io/collector/component v0.66.1-0.20221128222955-4ff1ff379b90
go.opentelemetry.io/collector/pdata v0.66.1-0.20221128222955-4ff1ff379b90
Expand All @@ -20,7 +21,6 @@ require (
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/knadh/koanf v1.4.4 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
Expand Down
4 changes: 3 additions & 1 deletion pkg/ottl/ottlfuncs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ The `IsMatch` factory function returns true if the `target` matches the regex `p

`target` is either a path expression to a telemetry field to retrieve or a literal string. `pattern` is a regexp pattern.

The function matches the target against the pattern, returning true if the match is successful and false otherwise. If target is nil or not a string false is always returned.
The function matches the target against the pattern, returning true if the match is successful and false otherwise.
If target is a boolean, int, or float it will be converted to a string.
If target is nil or not a string, boolean, int, or float false is always returned.

Examples:

Expand Down
37 changes: 33 additions & 4 deletions pkg/ottl/ottlfuncs/func_is_match.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@ package ottlfuncs // import "github.com/open-telemetry/opentelemetry-collector-c

import (
"context"
"encoding/base64"
"errors"
"fmt"
"regexp"
"strconv"

jsoniter "github.com/json-iterator/go"
"go.opentelemetry.io/collector/pdata/pcommon"

"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
)
Expand All @@ -32,11 +38,34 @@ func IsMatch[K any](target ottl.Getter[K], pattern string) (ottl.ExprFunc[K], er
if err != nil {
return nil, err
}
if val != nil {
if valStr, ok := val.(string); ok {
return compiledPattern.MatchString(valStr), nil

switch v := val.(type) {
case string:
return compiledPattern.MatchString(v), nil
case bool:
return compiledPattern.MatchString(strconv.FormatBool(v)), nil
case int64:
return compiledPattern.MatchString(strconv.FormatInt(v, 10)), nil
case float64:
return compiledPattern.MatchString(strconv.FormatFloat(v, 'f', -1, 64)), nil
case []byte:
return compiledPattern.MatchString(base64.StdEncoding.EncodeToString(v)), nil
case pcommon.Map:
result, err := jsoniter.MarshalToString(v.AsRaw())
if err != nil {
return nil, err
}
return compiledPattern.MatchString(result), nil
case pcommon.Slice:
result, err := jsoniter.MarshalToString(v.AsRaw())
if err != nil {
return nil, err
}
return compiledPattern.MatchString(result), nil
case pcommon.Value:
return compiledPattern.MatchString(v.AsString()), nil
default:
return nil, errors.New("unsupported type")
}
return false, nil
}, nil
}
54 changes: 45 additions & 9 deletions pkg/ottl/ottlfuncs/func_is_match_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/pdata/pcommon"

"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
)
Expand Down Expand Up @@ -62,31 +63,53 @@ func Test_isMatch(t *testing.T) {
expected: true,
},
{
name: "target not a string",
name: "target bool",
target: &ottl.StandardGetSetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return 1, nil
return true, nil
},
},
pattern: "doesnt matter will be false",
expected: false,
pattern: "true",
expected: true,
},
{
name: "target nil",
name: "target int",
target: &ottl.StandardGetSetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return nil, nil
return int64(1), nil
},
},
pattern: "doesnt matter will be false",
expected: false,
pattern: `\d`,
expected: true,
},
{
name: "target float",
target: &ottl.StandardGetSetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return 1.1, nil
},
},
pattern: `\d\.\d`,
expected: true,
},
{
name: "target pcommon.Value",
target: &ottl.StandardGetSetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
v := pcommon.NewValueEmpty()
v.SetStr("test")
return v, nil
},
},
pattern: `test`,
expected: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
exprFunc, err := IsMatch(tt.target, tt.pattern)
assert.NoError(t, err)
result, err := exprFunc(nil, nil)
result, err := exprFunc(context.Background(), nil)
assert.NoError(t, err)
assert.Equal(t, tt.expected, result)
})
Expand All @@ -102,3 +125,16 @@ func Test_isMatch_validation(t *testing.T) {
_, err := IsMatch[interface{}](target, "\\K")
require.Error(t, err)
}

func Test_isMatch_error(t *testing.T) {
target := &ottl.StandardGetSetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
v := ottl.Path{}
return v, nil
},
}
exprFunc, err := IsMatch[interface{}](target, "test")
assert.NoError(t, err)
_, err = exprFunc(context.Background(), nil)
require.Error(t, err)
}

0 comments on commit 855c243

Please sign in to comment.