Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pkg/ottl] Add PMapGetter for getting pdata maps #19781

Merged
merged 4 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .chloggen/ottl-use-mapgetter.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: breaking

# 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: Add typed getter for `pcommon.map` and update related functions to use it.

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

# (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: Using the impacted functions, such as `keep_keys` or `replace_all_patterns`, without a `pcommon.map` will now result in an error. Only pass these function paths that result in a `pcommon.map` or set `ErrorMode` to `IgnoreError`.
6 changes: 6 additions & 0 deletions pkg/ottl/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ package ottl // import "github.com/open-telemetry/opentelemetry-collector-contri
import (
"context"
"fmt"

"go.opentelemetry.io/collector/pdata/pcommon"
)

type ExprFunc[K any] func(ctx context.Context, tCtx K) (interface{}, error)
Expand Down Expand Up @@ -97,6 +99,10 @@ type IntGetter[K any] interface {
Get(ctx context.Context, tCtx K) (int64, error)
}

type PMapGetter[K any] interface {
Get(ctx context.Context, tCtx K) (pcommon.Map, error)
}

type StandardTypeGetter[K any, T any] struct {
Getter func(ctx context.Context, tCtx K) (interface{}, error)
}
Expand Down
14 changes: 14 additions & 0 deletions pkg/ottl/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"fmt"
"reflect"
"strings"

"go.opentelemetry.io/collector/pdata/pcommon"
)

type PathExpressionParser[K any] func(*Path) (GetSetter[K], error)
Expand Down Expand Up @@ -125,6 +127,12 @@ func (p *Parser[K]) buildSliceArg(argVal value, argType reflect.Type) (any, erro
return nil, err
}
return arg, nil
case strings.HasPrefix(name, "PMapGetter"):
arg, err := buildSlice[PMapGetter[K]](argVal, argType, p.buildArg, name)
if err != nil {
return nil, err
}
return arg, nil
case strings.HasPrefix(name, "StringGetter"):
arg, err := buildSlice[StringGetter[K]](argVal, argType, p.buildArg, name)
if err != nil {
Expand Down Expand Up @@ -169,6 +177,12 @@ func (p *Parser[K]) buildArg(argVal value, argType reflect.Type) (any, error) {
return nil, err
}
return StandardTypeGetter[K, int64]{Getter: arg.Get}, nil
case strings.HasPrefix(name, "PMapGetter"):
arg, err := p.newGetter(argVal)
if err != nil {
return nil, err
}
return StandardTypeGetter[K, pcommon.Map]{Getter: arg.Get}, nil
case name == "Enum":
arg, err := p.enumParser(argVal.Enum)
if err != nil {
Expand Down
71 changes: 71 additions & 0 deletions pkg/ottl/functions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,43 @@ func Test_NewFunctionCall(t *testing.T) {
},
want: 2,
},
{
name: "pmapgetter slice arg",
inv: invocation{
Function: "testing_pmapgetter_slice",
Arguments: []value{
{
List: &list{
Values: []value{
{
Literal: &mathExprLiteral{
Path: &Path{
Fields: []Field{
{
Name: "name",
},
},
},
},
},
{
Literal: &mathExprLiteral{
Path: &Path{
Fields: []Field{
{
Name: "name",
},
},
},
},
},
},
},
},
},
},
want: 2,
},
{
name: "setter arg",
inv: invocation{
Expand Down Expand Up @@ -671,6 +708,26 @@ func Test_NewFunctionCall(t *testing.T) {
},
want: nil,
},
{
name: "pmapgetter arg",
inv: invocation{
Function: "testing_pmapgetter",
Arguments: []value{
{
Literal: &mathExprLiteral{
Path: &Path{
Fields: []Field{
{
Name: "name",
},
},
},
},
},
},
},
want: nil,
},
{
name: "string arg",
inv: invocation{
Expand Down Expand Up @@ -908,6 +965,12 @@ func functionWithStringGetterSlice(getters []Getter[interface{}]) (ExprFunc[inte
}, nil
}

func functionWithPMapGetterSlice(getters []PMapGetter[interface{}]) (ExprFunc[interface{}], error) {
return func(context.Context, interface{}) (interface{}, error) {
return len(getters), nil
}, nil
}

func functionWithSetter(Setter[interface{}]) (ExprFunc[interface{}], error) {
return func(context.Context, interface{}) (interface{}, error) {
return "anything", nil
Expand Down Expand Up @@ -938,6 +1001,12 @@ func functionWithIntGetter(IntGetter[interface{}]) (ExprFunc[interface{}], error
}, nil
}

func functionWithPMapGetter(PMapGetter[interface{}]) (ExprFunc[interface{}], error) {
return func(context.Context, interface{}) (interface{}, error) {
return "anything", nil
}, nil
}

func functionWithString(string) (ExprFunc[interface{}], error) {
return func(context.Context, interface{}) (interface{}, error) {
return "anything", nil
Expand Down Expand Up @@ -1007,11 +1076,13 @@ func defaultFunctionsForTests() map[string]interface{} {
functions["testing_byte_slice"] = functionWithByteSlice
functions["testing_getter_slice"] = functionWithGetterSlice
functions["testing_stringgetter_slice"] = functionWithStringGetterSlice
functions["testing_pmapgetter_slice"] = functionWithPMapGetterSlice
functions["testing_setter"] = functionWithSetter
functions["testing_getsetter"] = functionWithGetSetter
functions["testing_getter"] = functionWithGetter
functions["testing_stringgetter"] = functionWithStringGetter
functions["testing_intgetter"] = functionWithIntGetter
functions["testing_pmapgetter"] = functionWithPMapGetter
functions["testing_string"] = functionWithString
functions["testing_float"] = functionWithFloat
functions["testing_int"] = functionWithInt
Expand Down
12 changes: 2 additions & 10 deletions pkg/ottl/ottlfuncs/func_delete_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,16 @@ package ottlfuncs // import "github.com/open-telemetry/opentelemetry-collector-c
import (
"context"

"go.opentelemetry.io/collector/pdata/pcommon"

"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
)

func DeleteKey[K any](target ottl.Getter[K], key string) (ottl.ExprFunc[K], error) {
func DeleteKey[K any](target ottl.PMapGetter[K], key string) (ottl.ExprFunc[K], error) {
return func(ctx context.Context, tCtx K) (interface{}, error) {
val, err := target.Get(ctx, tCtx)
if err != nil {
return nil, err
}
if val == nil {
return nil, nil
}

if attrs, ok := val.(pcommon.Map); ok {
attrs.Remove(key)
}
val.Remove(key)
return nil, nil
}, nil
}
27 changes: 8 additions & 19 deletions pkg/ottl/ottlfuncs/func_delete_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ func Test_deleteKey(t *testing.T) {
input.PutInt("test2", 3)
input.PutBool("test3", true)

target := &ottl.StandardGetSetter[pcommon.Map]{
target := &ottl.StandardTypeGetter[pcommon.Map, pcommon.Map]{
Getter: func(ctx context.Context, tCtx pcommon.Map) (interface{}, error) {
return tCtx, nil
},
}

tests := []struct {
name string
target ottl.Getter[pcommon.Map]
target ottl.PMapGetter[pcommon.Map]
key string
want func(pcommon.Map)
}{
Expand Down Expand Up @@ -92,42 +92,31 @@ func Test_deleteKey(t *testing.T) {

func Test_deleteKey_bad_input(t *testing.T) {
input := pcommon.NewValueStr("not a map")
target := &ottl.StandardGetSetter[interface{}]{
target := &ottl.StandardTypeGetter[interface{}, pcommon.Map]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return tCtx, nil
},
Setter: func(ctx context.Context, tCtx interface{}, val interface{}) error {
t.Errorf("nothing should be set in this scenario")
return nil
},
}

key := "anything"

exprFunc, err := DeleteKey[interface{}](target, key)
assert.NoError(t, err)
result, err := exprFunc(nil, input)
assert.NoError(t, err)
assert.Nil(t, result)
assert.Equal(t, pcommon.NewValueStr("not a map"), input)
_, err = exprFunc(nil, input)
assert.Error(t, err)
}

func Test_deleteKey_get_nil(t *testing.T) {
target := &ottl.StandardGetSetter[interface{}]{
target := &ottl.StandardTypeGetter[interface{}, pcommon.Map]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return tCtx, nil
},
Setter: func(ctx context.Context, tCtx interface{}, val interface{}) error {
t.Errorf("nothing should be set in this scenario")
return nil
},
}

key := "anything"

exprFunc, err := DeleteKey[interface{}](target, key)
assert.NoError(t, err)
result, err := exprFunc(nil, nil)
assert.NoError(t, err)
assert.Nil(t, result)
_, err = exprFunc(nil, nil)
assert.Error(t, err)
}
14 changes: 4 additions & 10 deletions pkg/ottl/ottlfuncs/func_delete_matching_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
)

func DeleteMatchingKeys[K any](target ottl.Getter[K], pattern string) (ottl.ExprFunc[K], error) {
func DeleteMatchingKeys[K any](target ottl.PMapGetter[K], pattern string) (ottl.ExprFunc[K], error) {
compiledPattern, err := regexp.Compile(pattern)
if err != nil {
return nil, fmt.Errorf("the regex pattern supplied to delete_matching_keys is not a valid pattern: %w", err)
Expand All @@ -34,15 +34,9 @@ func DeleteMatchingKeys[K any](target ottl.Getter[K], pattern string) (ottl.Expr
if err != nil {
return nil, err
}
if val == nil {
return nil, nil
}

if attrs, ok := val.(pcommon.Map); ok {
attrs.RemoveIf(func(key string, _ pcommon.Value) bool {
return compiledPattern.MatchString(key)
})
}
val.RemoveIf(func(key string, _ pcommon.Value) bool {
return compiledPattern.MatchString(key)
})
return nil, nil
}, nil
}
19 changes: 8 additions & 11 deletions pkg/ottl/ottlfuncs/func_delete_matching_keys_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ func Test_deleteMatchingKeys(t *testing.T) {
input.PutInt("test2", 3)
input.PutBool("test3", true)

target := &ottl.StandardGetSetter[pcommon.Map]{
target := &ottl.StandardTypeGetter[pcommon.Map, pcommon.Map]{
Getter: func(ctx context.Context, tCtx pcommon.Map) (interface{}, error) {
return tCtx, nil
},
}

tests := []struct {
name string
target ottl.Getter[pcommon.Map]
target ottl.PMapGetter[pcommon.Map]
pattern string
want func(pcommon.Map)
}{
Expand Down Expand Up @@ -91,7 +91,7 @@ func Test_deleteMatchingKeys(t *testing.T) {

func Test_deleteMatchingKeys_bad_input(t *testing.T) {
input := pcommon.NewValueInt(1)
target := &ottl.StandardGetSetter[interface{}]{
target := &ottl.StandardTypeGetter[interface{}, pcommon.Map]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return tCtx, nil
},
Expand All @@ -101,27 +101,24 @@ func Test_deleteMatchingKeys_bad_input(t *testing.T) {
assert.NoError(t, err)

_, err = exprFunc(nil, input)
assert.Nil(t, err)

assert.Equal(t, pcommon.NewValueInt(1), input)
assert.Error(t, err)
}

func Test_deleteMatchingKeys_get_nil(t *testing.T) {
target := &ottl.StandardGetSetter[interface{}]{
target := &ottl.StandardTypeGetter[interface{}, pcommon.Map]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return tCtx, nil
},
}

exprFunc, err := DeleteMatchingKeys[interface{}](target, "anything")
assert.NoError(t, err)
result, err := exprFunc(nil, nil)
assert.NoError(t, err)
assert.Nil(t, result)
_, err = exprFunc(nil, nil)
assert.Error(t, err)
}

func Test_deleteMatchingKeys_invalid_pattern(t *testing.T) {
target := &ottl.StandardGetSetter[interface{}]{
target := &ottl.StandardTypeGetter[interface{}, pcommon.Map]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
t.Errorf("nothing should be received in this scenario")
return nil, nil
Expand Down
20 changes: 7 additions & 13 deletions pkg/ottl/ottlfuncs/func_keep_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
)

func KeepKeys[K any](target ottl.GetSetter[K], keys []string) (ottl.ExprFunc[K], error) {
func KeepKeys[K any](target ottl.PMapGetter[K], keys []string) (ottl.ExprFunc[K], error) {
keySet := make(map[string]struct{}, len(keys))
for _, key := range keys {
keySet[key] = struct{}{}
Expand All @@ -33,18 +33,12 @@ func KeepKeys[K any](target ottl.GetSetter[K], keys []string) (ottl.ExprFunc[K],
if err != nil {
return nil, err
}
if val == nil {
return nil, nil
}

if attrs, ok := val.(pcommon.Map); ok {
attrs.RemoveIf(func(key string, value pcommon.Value) bool {
_, ok := keySet[key]
return !ok
})
if attrs.Len() == 0 {
attrs.Clear()
}
val.RemoveIf(func(key string, value pcommon.Value) bool {
_, ok := keySet[key]
return !ok
})
if val.Len() == 0 {
val.Clear()
}
return nil, nil
}, nil
Expand Down
Loading