Skip to content

Commit

Permalink
[pkg/ottl] Fix handling of slice values in flatten function by cons…
Browse files Browse the repository at this point in the history
…idering `depth` option (open-telemetry#36198)

<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue.
Ex. Adding a feature - Explain what this achieves.-->
#### Description

This PR adapts the `flatten` function to also consider the `depth`
option when handling slice values. Before this change, the function
flattened slice values beyond the given depth.

<!-- Issue number (e.g. open-telemetry#1234) or full URL to issue, if applicable. -->
#### Link to tracking issue
Fixes open-telemetry#36161 

<!--Describe what testing was performed and which tests were added.-->
#### Testing

Added unit and e2e tests

<!--Describe the documentation added.-->
#### Documentation

No changes here, as the docs already mention the expected behavior of
the function when the `depth` option is set
<!--Please delete paragraphs that you did not use before submitting.-->

---------

Signed-off-by: Florian Bacher <florian.bacher@dynatrace.com>
Co-authored-by: Evan Bradley <11745660+evan-bradley@users.noreply.github.com>
  • Loading branch information
2 people authored and RutvikS-crest committed Dec 9, 2024
1 parent 4d9dad8 commit 10aa506
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 22 deletions.
27 changes: 27 additions & 0 deletions .chloggen/ottl-flatten-fix-top-level-slice-handling.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: bug_fix

# 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: Respect the `depth` option when flattening slices using `flatten`

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

# (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 `depth` option is also now required to be at least `1`.

# 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: []
15 changes: 1 addition & 14 deletions pkg/ottl/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,19 +105,6 @@ func Test_e2e_editors(t *testing.T) {
m.CopyTo(tCtx.GetLogRecord().Attributes())
},
},
{
statement: `flatten(attributes, depth=0)`,
want: func(tCtx ottllog.TransformContext) {
tCtx.GetLogRecord().Attributes().Remove("things")
m1 := tCtx.GetLogRecord().Attributes().PutEmptyMap("things.0")
m1.PutStr("name", "foo")
m1.PutInt("value", 2)

m2 := tCtx.GetLogRecord().Attributes().PutEmptyMap("things.1")
m2.PutStr("name", "bar")
m2.PutInt("value", 5)
},
},
{
statement: `flatten(attributes, depth=1)`,
want: func(tCtx ottllog.TransformContext) {
Expand All @@ -131,7 +118,7 @@ func Test_e2e_editors(t *testing.T) {
m.PutStr("foo.flags", "pass")
m.PutStr("foo.bar", "pass")
m.PutStr("foo.flags", "pass")
m.PutStr("foo.slice.0", "val")
m.PutEmptySlice("foo.slice").AppendEmpty().SetStr("val")

m1 := m.PutEmptyMap("things.0")
m1.PutStr("name", "foo")
Expand Down
6 changes: 3 additions & 3 deletions pkg/ottl/ottlfuncs/func_flatten.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ func flatten[K any](target ottl.PMapGetter[K], p ottl.Optional[string], d ottl.O
depth := int64(math.MaxInt64)
if !d.IsEmpty() {
depth = d.Get()
if depth < 0 {
return nil, fmt.Errorf("invalid depth for flatten function, %d cannot be negative", depth)
if depth < 1 {
return nil, fmt.Errorf("invalid depth '%d' for flatten function, must be greater than 0", depth)
}
}

Expand Down Expand Up @@ -69,7 +69,7 @@ func flattenHelper(m pcommon.Map, result pcommon.Map, prefix string, currentDept
switch {
case v.Type() == pcommon.ValueTypeMap && currentDepth < maxDepth:
flattenHelper(v.Map(), result, prefix+k, currentDepth+1, maxDepth)
case v.Type() == pcommon.ValueTypeSlice:
case v.Type() == pcommon.ValueTypeSlice && currentDepth < maxDepth:
for i := 0; i < v.Slice().Len(); i++ {
v.Slice().At(i).CopyTo(result.PutEmpty(fmt.Sprintf("%v.%v", prefix+k, i)))
}
Expand Down
61 changes: 56 additions & 5 deletions pkg/ottl/ottlfuncs/func_flatten_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,39 @@ func Test_flatten(t *testing.T) {
},
},
},
{
name: "max depth with slice",
target: map[string]any{
"0": map[string]any{
"1": map[string]any{
"2": map[string]any{
"3": "value",
},
},
},
"1": map[string]any{
"1": []any{
map[string]any{
"1": "value",
},
},
},
},
prefix: ottl.Optional[string]{},
depth: ottl.NewTestingOptional[int64](1),
expected: map[string]any{
"0.1": map[string]any{
"2": map[string]any{
"3": "value",
},
},
"1.1": []any{
map[string]any{
"1": "value",
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -179,11 +212,29 @@ func Test_flatten_bad_target(t *testing.T) {
}

func Test_flatten_bad_depth(t *testing.T) {
target := &ottl.StandardPMapGetter[any]{
Getter: func(_ context.Context, _ any) (any, error) {
return pcommon.NewMap(), nil
tests := []struct {
name string
depth ottl.Optional[int64]
}{
{
name: "negative depth",
depth: ottl.NewTestingOptional[int64](-1),
},
{
name: "zero depth",
depth: ottl.NewTestingOptional[int64](0),
},
}
_, err := flatten[any](target, ottl.Optional[string]{}, ottl.NewTestingOptional[int64](-1))
assert.Error(t, err)

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
target := &ottl.StandardPMapGetter[any]{
Getter: func(_ context.Context, _ any) (any, error) {
return pcommon.NewMap(), nil
},
}
_, err := flatten[any](target, ottl.Optional[string]{}, tt.depth)
assert.Error(t, err)
})
}
}

0 comments on commit 10aa506

Please sign in to comment.