Skip to content

Commit 1664ed8

Browse files
committed
[pkg/ottl] Add Base64Decode function (open-telemetry#31543)
**Description:** Adds a new `Base64Decode` function to facilitate ingest of base64 encoded data **Link to tracking Issue:** open-telemetry#31543 **Testing:** Added unit test **Documentation:** Updated the func readme.
1 parent 77a9540 commit 1664ed8

File tree

5 files changed

+171
-0
lines changed

5 files changed

+171
-0
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: ottl
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: "Add new function to decode a base64 encoded string and output the original string"
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [31543]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []

pkg/ottl/ottlfuncs/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ Unlike functions, they do not modify any input telemetry and always return a val
377377

378378
Available Converters:
379379

380+
- [Base64Decode](#base64decode)
380381
- [Concat](#concat)
381382
- [ConvertCase](#convertcase)
382383
- [ExtractPatterns](#extractpatterns)
@@ -417,6 +418,21 @@ Available Converters:
417418
- [UnixSeconds](#unixseconds)
418419
- [UUID](#UUID)
419420

421+
### Base64Decode
422+
423+
`Base64Decode(value)`
424+
425+
The `Base64Decode` Converter takes a base64 encoded string and returns the decoded string.
426+
427+
`value` is a valid base64 encoded string.
428+
429+
Examples:
430+
431+
- `Base64Decode("aGVsbG8gd29ybGQ=")`
432+
433+
434+
- `Base64Decode(attributes["encoded field"])`
435+
420436
### Concat
421437

422438
`Concat(values[], delimiter)`
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package ottlfuncs // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs"
5+
6+
import (
7+
"context"
8+
"encoding/base64"
9+
"fmt"
10+
11+
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
12+
)
13+
14+
type Base64DecodeArguments[K any] struct {
15+
Target ottl.StringGetter[K]
16+
}
17+
18+
func NewBase64DecodeFactory[K any]() ottl.Factory[K] {
19+
return ottl.NewFactory("Base64Decode", &Base64DecodeArguments[K]{}, createBase64DecodeFunction[K])
20+
}
21+
22+
func createBase64DecodeFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
23+
args, ok := oArgs.(*Base64DecodeArguments[K])
24+
25+
if !ok {
26+
return nil, fmt.Errorf("Base64DecodeFactory args must be of type *Base64DecodeArguments[K]")
27+
}
28+
29+
return Base64Decode(args.Target)
30+
}
31+
32+
func Base64Decode[K any](target ottl.StringGetter[K]) (ottl.ExprFunc[K], error) {
33+
34+
return func(ctx context.Context, tCtx K) (any, error) {
35+
val, err := target.Get(ctx, tCtx)
36+
if err != nil {
37+
return nil, err
38+
}
39+
base64string, err := base64.StdEncoding.DecodeString(val)
40+
if err != nil {
41+
return nil, err
42+
}
43+
return string(base64string), nil
44+
}, nil
45+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package ottlfuncs
5+
6+
import (
7+
"context"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
12+
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
13+
)
14+
15+
func Test_Base64Decode(t *testing.T) {
16+
tests := []struct {
17+
name string
18+
value any
19+
expected any
20+
err bool
21+
}{
22+
{
23+
name: "base64-string",
24+
value: "aGVsbG8gd29ybGQ=",
25+
expected: "hello world",
26+
},
27+
{
28+
name: "empty string",
29+
value: "",
30+
expected: "",
31+
},
32+
}
33+
for _, tt := range tests {
34+
t.Run(tt.name, func(t *testing.T) {
35+
exprFunc, err := Base64Decode[any](&ottl.StandardStringGetter[any]{
36+
Getter: func(context.Context, any) (any, error) {
37+
return tt.value, nil
38+
},
39+
})
40+
assert.NoError(t, err)
41+
result, err := exprFunc(nil, nil)
42+
if tt.err {
43+
assert.Error(t, err)
44+
} else {
45+
assert.NoError(t, err)
46+
}
47+
assert.Equal(t, tt.expected, result)
48+
})
49+
}
50+
}
51+
52+
func Test_Base64DecodeError(t *testing.T) {
53+
tests := []struct {
54+
name string
55+
value any
56+
err bool
57+
expectedError string
58+
}{
59+
{
60+
name: "non-string",
61+
value: 10,
62+
expectedError: "expected string but got int",
63+
},
64+
{
65+
name: "nil",
66+
value: nil,
67+
expectedError: "expected string but got nil",
68+
},
69+
}
70+
for _, tt := range tests {
71+
t.Run(tt.name, func(t *testing.T) {
72+
exprFunc, err := Base64Decode[any](&ottl.StandardStringGetter[any]{
73+
Getter: func(context.Context, any) (any, error) {
74+
return tt.value, nil
75+
},
76+
})
77+
assert.NoError(t, err)
78+
_, err = exprFunc(nil, nil)
79+
assert.ErrorContains(t, err, tt.expectedError)
80+
})
81+
}
82+
}

pkg/ottl/ottlfuncs/functions.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func StandardConverters[K any]() map[string]ottl.Factory[K] {
3535
func converters[K any]() []ottl.Factory[K] {
3636
return []ottl.Factory[K]{
3737
// Converters
38+
NewBase64DecodeFactory[K](),
3839
NewConcatFactory[K](),
3940
NewConvertCaseFactory[K](),
4041
NewDoubleFactory[K](),

0 commit comments

Comments
 (0)