diff --git a/.chloggen/ottl-add-ProfileID-function.yaml b/.chloggen/ottl-add-ProfileID-function.yaml new file mode 100644 index 000000000000..e8b36f1721e9 --- /dev/null +++ b/.chloggen/ottl-add-ProfileID-function.yaml @@ -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: Add the OTTL function ProfileID() + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [39587] + +# (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] diff --git a/pkg/ottl/e2e/e2e_test.go b/pkg/ottl/e2e/e2e_test.go index dbce51e1a9fe..56a3a6dc9d60 100644 --- a/pkg/ottl/e2e/e2e_test.go +++ b/pkg/ottl/e2e/e2e_test.go @@ -997,6 +997,12 @@ func Test_e2e_converters(t *testing.T) { tCtx.GetLogRecord().SetSpanID(pcommon.NewSpanIDEmpty()) }, }, + { + statement: `set(attributes["test"], "pass") where String(ProfileID(0x00000000000000000000000000000001)) == "[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]"`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, { statement: `set(attributes["test"], Split(attributes["flags"], "|"))`, want: func(tCtx ottllog.TransformContext) { diff --git a/pkg/ottl/ottlfuncs/README.md b/pkg/ottl/ottlfuncs/README.md index cdecc5855f99..54e879bfcdd0 100644 --- a/pkg/ottl/ottlfuncs/README.md +++ b/pkg/ottl/ottlfuncs/README.md @@ -500,6 +500,7 @@ Available Converters: - [ParseKeyValue](#parsekeyvalue) - [ParseSimplifiedXML](#parsesimplifiedxml) - [ParseXML](#parsexml) +- [ProfileID](#profileid) - [RemoveXML](#removexml) - [Second](#second) - [Seconds](#seconds) @@ -1714,6 +1715,18 @@ Examples: - `ParseXML("")` +### ProfileID + +`ProfileID(bytes)` + +The `ProfileID` Converter returns a `pprofile.ProfileID` struct from the given byte slice. + +`bytes` is a byte slice of exactly 16 bytes. + +Examples: + +- `ProfileID(0x00112233445566778899aabbccddeeff)` + ### RemoveXML `RemoveXML(target, xpath)` diff --git a/pkg/ottl/ottlfuncs/func_profile_id.go b/pkg/ottl/ottlfuncs/func_profile_id.go new file mode 100644 index 000000000000..25e50cbcd300 --- /dev/null +++ b/pkg/ottl/ottlfuncs/func_profile_id.go @@ -0,0 +1,43 @@ +// 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" + "errors" + "fmt" + + "go.opentelemetry.io/collector/pdata/pprofile" + + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" +) + +type ProfileIDArguments[K any] struct { + Bytes []byte +} + +func NewProfileIDFactory[K any]() ottl.Factory[K] { + return ottl.NewFactory("ProfileID", &ProfileIDArguments[K]{}, createProfileIDFunction[K]) +} + +func createProfileIDFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) { + args, ok := oArgs.(*ProfileIDArguments[K]) + + if !ok { + return nil, errors.New("ProfileIDFactory args must be of type *ProfileIDArguments[K]") + } + + return profileID[K](args.Bytes) +} + +func profileID[K any](bytes []byte) (ottl.ExprFunc[K], error) { + id := pprofile.ProfileID{} + if len(bytes) != len(id) { + return nil, fmt.Errorf("profile ids must be %d bytes", len(id)) + } + copy(id[:], bytes) + return func(context.Context, K) (any, error) { + return id, nil + }, nil +} diff --git a/pkg/ottl/ottlfuncs/func_profile_id_test.go b/pkg/ottl/ottlfuncs/func_profile_id_test.go new file mode 100644 index 000000000000..e94bf11773e1 --- /dev/null +++ b/pkg/ottl/ottlfuncs/func_profile_id_test.go @@ -0,0 +1,66 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package ottlfuncs + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/pdata/pprofile" +) + +func Test_profileID(t *testing.T) { + tests := []struct { + name string + bytes []byte + want pprofile.ProfileID + }{ + { + name: "create profile id", + bytes: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, + want: pprofile.ProfileID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + exprFunc, err := profileID[any](tt.bytes) + assert.NoError(t, err) + result, err := exprFunc(nil, nil) + assert.NoError(t, err) + assert.Equal(t, tt.want, result) + }) + } +} + +func Test_profileID_validation(t *testing.T) { + tests := []struct { + name string + bytes []byte + err string + }{ + { + name: "nil profile id", + bytes: nil, + err: "profile ids must be 16 bytes", + }, + { + name: "byte slice less than 16", + bytes: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + err: "profile ids must be 16 bytes", + }, + { + name: "byte slice longer than 16", + bytes: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, + err: "profile ids must be 16 bytes", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := profileID[any](tt.bytes) + require.Error(t, err) + assert.ErrorContains(t, err, tt.err) + }) + } +} diff --git a/pkg/ottl/ottlfuncs/functions.go b/pkg/ottl/ottlfuncs/functions.go index 0a720a29cf52..524d86655279 100644 --- a/pkg/ottl/ottlfuncs/functions.go +++ b/pkg/ottl/ottlfuncs/functions.go @@ -114,5 +114,6 @@ func converters[K any]() []ottl.Factory[K] { NewYearFactory[K](), NewHexFactory[K](), NewSliceToMapFactory[K](), + NewProfileIDFactory[K](), } }