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] Support for append #33017

Merged
merged 37 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
657da3c
Support for append
michalpristas May 13, 2024
c45dd97
readme
michalpristas May 13, 2024
acf1fdc
Merge branch 'main' of github.com:open-telemetry/opentelemetry-collec…
michalpristas May 13, 2024
8083a80
added changelog fragment
michalpristas May 13, 2024
48dceaf
allow mixed types
michalpristas May 14, 2024
274d6ee
check fromRaw errors
michalpristas May 14, 2024
fe40206
Merge branch 'main' of github.com:open-telemetry/opentelemetry-collec…
michalpristas May 14, 2024
303b0cd
type check when appending. guarantee of same type
michalpristas May 15, 2024
8e20659
Revert "type check when appending. guarantee of same type"
michalpristas May 25, 2024
5d7d59c
resolved conflicts with main
michalpristas May 25, 2024
04f0ff1
Merge branch 'main' of github.com:open-telemetry/opentelemetry-collec…
michalpristas May 30, 2024
526d88b
Update pkg/ottl/ottlfuncs/func_append.go
michalpristas May 30, 2024
df0f75e
Merge branch 'ottl/append' of github.com:michalpristas/opentelemetry-…
michalpristas May 30, 2024
148f77a
cleanup
michalpristas May 30, 2024
a1d124c
updated append tests
michalpristas May 30, 2024
859b095
added e2e tests for append
michalpristas May 30, 2024
d5764a1
Merge branch 'main' into ottl/append
michalpristas May 30, 2024
781a848
Merge branch 'main' into ottl/append
michalpristas May 31, 2024
8dfaa8b
Merge branch 'main' into ottl/append
michalpristas May 31, 2024
de7248c
do not export Append
michalpristas May 31, 2024
4461d62
Merge branch 'ottl/append' of github.com:michalpristas/opentelemetry-…
michalpristas May 31, 2024
b4e1f34
pass res as tCtx
michalpristas May 31, 2024
5b47882
Merge branch 'main' of github.com:open-telemetry/opentelemetry-collec…
michalpristas May 31, 2024
7e337fe
use transform context for res
michalpristas May 31, 2024
b78e8ee
fix lint
michalpristas May 31, 2024
2c7a5b6
Merge branch 'main' of github.com:open-telemetry/opentelemetry-collec…
michalpristas May 31, 2024
be2932c
Merge branch 'main' into ottl/append
michalpristas Jun 3, 2024
2c388bf
Apply suggestions from code review
michalpristas Jun 5, 2024
b7cbd71
target type tests
michalpristas Jun 5, 2024
f132e48
Merge branch 'main' into ottl/append
michalpristas Jun 5, 2024
3d85d05
linting issue fixed
michalpristas Jun 6, 2024
0a50d04
Merge branch 'main' of github.com:open-telemetry/opentelemetry-collec…
michalpristas Jun 6, 2024
4cda3ce
Merge branch 'ottl/append' of github.com:michalpristas/opentelemetry-…
michalpristas Jun 6, 2024
24fb99b
Update pkg/ottl/ottlfuncs/README.md
michalpristas Jun 6, 2024
77d851c
Merge branch 'main' into ottl/append
michalpristas Jun 7, 2024
e18633f
Update pkg/ottl/ottlfuncs/README.md
michalpristas Jun 10, 2024
37ae200
Update pkg/ottl/ottlfuncs/README.md
michalpristas Jun 10, 2024
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
27 changes: 27 additions & 0 deletions .chloggen/ottl_append.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# 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: Introducing `append` function for appending items into an existing array

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

# (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:

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: [user]
39 changes: 39 additions & 0 deletions pkg/ottl/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,45 @@ func Test_e2e_editors(t *testing.T) {
tCtx.GetLogRecord().Attributes().PutStr("total.string", "1")
},
},
{
statement: `append(attributes["foo"]["slice"], "sample_value")`,
want: func(tCtx ottllog.TransformContext) {
v, _ := tCtx.GetLogRecord().Attributes().Get("foo")
sv, _ := v.Map().Get("slice")
s := sv.Slice()
s.AppendEmpty().SetStr("sample_value")

},
},
{
statement: `append(attributes["foo"]["flags"], "sample_value")`,
want: func(tCtx ottllog.TransformContext) {
v, _ := tCtx.GetLogRecord().Attributes().Get("foo")
s := v.Map().PutEmptySlice("flags")
s.AppendEmpty().SetStr("pass")
s.AppendEmpty().SetStr("sample_value")

},
},
{
statement: `append(attributes["foo"]["slice"], values=[5,6])`,
want: func(tCtx ottllog.TransformContext) {
v, _ := tCtx.GetLogRecord().Attributes().Get("foo")
sv, _ := v.Map().Get("slice")
s := sv.Slice()
s.AppendEmpty().SetInt(5)
s.AppendEmpty().SetInt(6)
},
},
{
statement: `append(attributes["foo"]["new_slice"], values=[5,6])`,
want: func(tCtx ottllog.TransformContext) {
v, _ := tCtx.GetLogRecord().Attributes().Get("foo")
s := v.Map().PutEmptySlice("new_slice")
s.AppendEmpty().SetInt(5)
s.AppendEmpty().SetInt(6)
},
},
}

for _, tt := range tests {
Expand Down
14 changes: 14 additions & 0 deletions pkg/ottl/ottlfuncs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Editors:

Available Editors:

- [append](#append)
- [delete_key](#delete_key)
- [delete_matching_keys](#delete_matching_keys)
- [flatten](#flatten)
Expand All @@ -58,6 +59,19 @@ Available Editors:
- [set](#set)
- [truncate_all](#truncate_all)

### append

`append(target, Optional[value], Optional[values])`
TylerHelmuth marked this conversation as resolved.
Show resolved Hide resolved

The `append` function appens single or multiple string values to target.
michalpristas marked this conversation as resolved.
Show resolved Hide resolved
`append` converts scalar values into an array if the field exists but is not an array and creates an array containing the provided values if the field doesn’t exist.
michalpristas marked this conversation as resolved.
Show resolved Hide resolved

Resulting field is always of type `pcommon.Slice` keeping types of existing values appending values as set not performing any conversions.
michalpristas marked this conversation as resolved.
Show resolved Hide resolved

- `append(attributes["tags"], "prod")`
- `append(attributes["tags"], values = ["staging", "staging:east"])`
- `append(attributes["tags_copy"], attributes["tags"])`

### delete_key

`delete_key(target, key)`
Expand Down
134 changes: 134 additions & 0 deletions pkg/ottl/ottlfuncs/func_append.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package ottlfuncs // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs"

import (
"context"
"fmt"

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

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

type AppendArguments[K any] struct {
Target ottl.GetSetter[K]
Value ottl.Optional[ottl.Getter[K]]
Values ottl.Optional[[]ottl.Getter[K]]
}

func NewAppendFactory[K any]() ottl.Factory[K] {
return ottl.NewFactory("append", &AppendArguments[K]{}, createAppendFunction[K])
}
func createAppendFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
args, ok := oArgs.(*AppendArguments[K])
if !ok {
return nil, fmt.Errorf("AppendFactory args must be of type *Appendrguments[K]")
}

return appendTo(args.Target, args.Value, args.Values)
}

func appendTo[K any](target ottl.GetSetter[K], value ottl.Optional[ottl.Getter[K]], values ottl.Optional[[]ottl.Getter[K]]) (ottl.ExprFunc[K], error) {
if value.IsEmpty() && values.IsEmpty() {
return nil, fmt.Errorf("at least one of the optional arguments must be provided be provided")
michalpristas marked this conversation as resolved.
Show resolved Hide resolved
}

return func(ctx context.Context, tCtx K) (any, error) {
t, err := target.Get(ctx, tCtx)
if err != nil {
return nil, err
}

// init res with target values
var res []any

if t != nil {
switch targetType := t.(type) {
evan-bradley marked this conversation as resolved.
Show resolved Hide resolved
case pcommon.Slice:
res = append(res, targetType.AsRaw()...)
case pcommon.Value:
switch targetType.Type() {
case pcommon.ValueTypeEmpty:
res = append(res, targetType.Str())
case pcommon.ValueTypeStr:
res = append(res, targetType.Str())
case pcommon.ValueTypeInt:
res = append(res, targetType.Int())
case pcommon.ValueTypeDouble:
res = append(res, targetType.Double())
case pcommon.ValueTypeBool:
res = append(res, targetType.Bool())
case pcommon.ValueTypeSlice:
res = append(res, targetType.Slice().AsRaw()...)
default:
return nil, fmt.Errorf("unsupported type of target field")
michalpristas marked this conversation as resolved.
Show resolved Hide resolved
}

case []string:
res = appendMultiple(res, targetType)
case []any:
res = append(res, targetType...)
case []int64:
res = appendMultiple(res, targetType)
case []bool:
res = appendMultiple(res, targetType)
case []float64:
res = appendMultiple(res, targetType)

case string:
res = append(res, targetType)
case int64:
res = append(res, targetType)
case bool:
res = append(res, targetType)
case float64:
res = append(res, targetType)
case any:
res = append(res, targetType)
default:
return nil, fmt.Errorf("unsupported type of target field")
michalpristas marked this conversation as resolved.
Show resolved Hide resolved
}
}

appendGetterFn := func(g ottl.Getter[K]) error {
v, err := g.Get(ctx, tCtx)
if err != nil {
return err
}
res = append(res, v)
TylerHelmuth marked this conversation as resolved.
Show resolved Hide resolved
return nil
}

if !value.IsEmpty() {
getter := value.Get()
if err := appendGetterFn(getter); err != nil {
return nil, err
}
}
if !values.IsEmpty() {
getters := values.Get()
for _, g := range getters {
if err := appendGetterFn(g); err != nil {
return nil, err
}
}
}

// retype []any to Slice, having []any sometimes misbehaves and nils pcommon.Value
resSlice := pcommon.NewSlice()
if err := resSlice.FromRaw(res); err != nil {
return nil, err
}

return nil, target.Set(ctx, tCtx, resSlice)
}, nil
}

func appendMultiple[K any](target []any, values []K) []any {
for _, v := range values {
target = append(target, v)
}
return target
}
Loading