Skip to content

Commit 4e91206

Browse files
authored
[pkg/ottl] Add Hex() convertor (#33450)
**Description:** <Describe what has changed.> Adds a Hex function to the OTTL package. This function can be applied to following values: - float64 - string - bool - int64 - []byte The resulting value will be of type []byte. **Link to tracking Issue:** #31929 **Testing:** - unit tests - e2e tests Depends on #33536 --------- Signed-off-by: odubajDT <[email protected]>
1 parent 21739a1 commit 4e91206

File tree

6 files changed

+196
-0
lines changed

6 files changed

+196
-0
lines changed

.chloggen/add-hex-function.yaml

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: pkg/ottl
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Added Hex() converter function
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: [31929]
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/e2e/e2e_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,30 @@ func Test_e2e_converters(t *testing.T) {
417417
tCtx.GetLogRecord().Attributes().PutInt("test", 1)
418418
},
419419
},
420+
{
421+
statement: `set(attributes["test"], Hex(1.0))`,
422+
want: func(tCtx ottllog.TransformContext) {
423+
tCtx.GetLogRecord().Attributes().PutStr("test", "3ff0000000000000")
424+
},
425+
},
426+
{
427+
statement: `set(attributes["test"], Hex(true))`,
428+
want: func(tCtx ottllog.TransformContext) {
429+
tCtx.GetLogRecord().Attributes().PutStr("test", "01")
430+
},
431+
},
432+
{
433+
statement: `set(attributes["test"], Hex(12))`,
434+
want: func(tCtx ottllog.TransformContext) {
435+
tCtx.GetLogRecord().Attributes().PutStr("test", "000000000000000c")
436+
},
437+
},
438+
{
439+
statement: `set(attributes["test"], Hex("12"))`,
440+
want: func(tCtx ottllog.TransformContext) {
441+
tCtx.GetLogRecord().Attributes().PutStr("test", "3132")
442+
},
443+
},
420444
{
421445
statement: `set(attributes["test"], "pass") where IsBool(false)`,
422446
want: func(tCtx ottllog.TransformContext) {

pkg/ottl/ottlfuncs/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,7 @@ Available Converters:
415415
- [Day](#day)
416416
- [ExtractPatterns](#extractpatterns)
417417
- [FNV](#fnv)
418+
- [Hex](#hex)
418419
- [Hour](#hour)
419420
- [Hours](#hours)
420421
- [Double](#double)
@@ -604,6 +605,33 @@ Examples:
604605

605606
- `FNV("name")`
606607

608+
### Hex
609+
610+
`Hex(value)`
611+
612+
The `Hex` converter converts the `value` to its hexadecimal representation.
613+
614+
The returned type is string representation of the hexadecimal value.
615+
616+
The input `value` types:
617+
618+
- float64 (`1.1` will result to `0x3ff199999999999a`)
619+
- string (`"1"` will result in `0x31`)
620+
- bool (`true` will result in `0x01`; `false` to `0x00`)
621+
- int64 (`12` will result in `0xC`)
622+
- []byte (without any changes - `0x02` will result to `0x02`)
623+
624+
If `value` is another type or parsing failed nil is always returned.
625+
626+
The `value` is either a path expression to a telemetry field to retrieve or a literal.
627+
628+
Examples:
629+
630+
- `Hex(attributes["http.status_code"])`
631+
632+
633+
- `Hex(2.0)`
634+
607635
### Hour
608636

609637
`Hour(value)`

pkg/ottl/ottlfuncs/func_hex.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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/hex"
9+
"fmt"
10+
11+
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
12+
)
13+
14+
type HexArguments[K any] struct {
15+
Target ottl.ByteSliceLikeGetter[K]
16+
}
17+
18+
func NewHexFactory[K any]() ottl.Factory[K] {
19+
return ottl.NewFactory("Hex", &HexArguments[K]{}, createHexFunction[K])
20+
}
21+
22+
func createHexFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
23+
args, ok := oArgs.(*HexArguments[K])
24+
25+
if !ok {
26+
return nil, fmt.Errorf("HexFactory args must be of type *HexArguments[K]")
27+
}
28+
29+
return Hex(args.Target)
30+
}
31+
32+
func Hex[K any](target ottl.ByteSliceLikeGetter[K]) (ottl.ExprFunc[K], error) {
33+
return func(ctx context.Context, tCtx K) (any, error) {
34+
value, err := target.Get(ctx, tCtx)
35+
if err != nil {
36+
return nil, err
37+
}
38+
return hex.EncodeToString(value), nil
39+
}, nil
40+
}

pkg/ottl/ottlfuncs/func_hex_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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 TestHex(t *testing.T) {
16+
type args struct {
17+
target ottl.ByteSliceLikeGetter[any]
18+
}
19+
type testCase struct {
20+
name string
21+
args args
22+
wantFunc func() any
23+
wantErr error
24+
}
25+
tests := []testCase{
26+
{
27+
name: "int64",
28+
args: args{
29+
target: &ottl.StandardByteSliceLikeGetter[any]{
30+
Getter: func(_ context.Context, _ any) (any, error) {
31+
return int64(12), nil
32+
},
33+
},
34+
},
35+
wantFunc: func() any {
36+
return "000000000000000c"
37+
},
38+
},
39+
{
40+
name: "nil",
41+
args: args{
42+
target: &ottl.StandardByteSliceLikeGetter[any]{
43+
Getter: func(_ context.Context, _ any) (any, error) {
44+
return nil, nil
45+
},
46+
},
47+
},
48+
wantFunc: func() any {
49+
return ""
50+
},
51+
wantErr: nil,
52+
},
53+
{
54+
name: "error",
55+
args: args{
56+
target: &ottl.StandardByteSliceLikeGetter[any]{
57+
Getter: func(_ context.Context, _ any) (any, error) {
58+
return map[string]string{"hi": "hi"}, nil
59+
},
60+
},
61+
},
62+
wantFunc: func() any {
63+
return nil
64+
},
65+
wantErr: ottl.TypeError("unsupported type: map[string]string"),
66+
},
67+
}
68+
for _, tt := range tests {
69+
t.Run(tt.name, func(t *testing.T) {
70+
expressionFunc, _ := Hex(tt.args.target)
71+
got, err := expressionFunc(context.Background(), tt.args)
72+
assert.Equal(t, tt.wantErr, err)
73+
assert.Equal(t, tt.wantFunc(), got)
74+
})
75+
}
76+
}

pkg/ottl/ottlfuncs/functions.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,5 +86,6 @@ func converters[K any]() []ottl.Factory[K] {
8686
NewURLFactory[K](),
8787
NewAppendFactory[K](),
8888
NewYearFactory[K](),
89+
NewHexFactory[K](),
8990
}
9091
}

0 commit comments

Comments
 (0)