Skip to content

[chore][pkg/ottl] Add OTTL context utilities for handling slices accessors #38928

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

Merged

Conversation

edmocosta
Copy link
Contributor

@edmocosta edmocosta commented Mar 24, 2025

Description

Currently, OTTL contexts setters can received different data type when using slices, which might lead to unexpected outcomes, for example, slice setters functions can receive the following value types:

  • []any when set from literals: set(string_table, ["foo", "bar"])
    • integer values within the []any are parsed as int64
  • []T when copied from another path: set(slice_path, slice_path)
  • pcommon.Slice when set from an map's key value: set(slice_path, resource.attributes["slice"])

Those different possibilities must be properly handled on the setter assessors, and are not obvious since the value is any-wrapped. Failing to handle all those possible types results in the path not being set or errors.

This PR adds a set of functions that helps setting and getting slices values, making it easier handling them until OTTL slice parsing is not standardized. Those functions will be especially useful for the new profile context (#37574), which needs to provide access to different pdata typed slices.

We've recently done something similar to maps (#38434).

Usage examples:

// tCtx.GetProfile().StringTable() -> pcommon.StringSlice
func accessStringTableKey[K ProfileContext](ctx context.Context, keys []ottl.Key[K]) ottl.StandardGetSetter[K] {
	return ottl.StandardGetSetter[K]{
		Getter: func(_ context.Context, tCtx K) (any, error) {
			return ctxutil.GetCommonTypedSliceValue[K, string](ctx, tCtx, tCtx.GetProfile().StringTable(), keys)
		},
		Setter: func(_ context.Context, tCtx K, val any) error {
			return ctxutil.SetCommonTypedSliceValue[K, string](ctx, tCtx, tCtx.GetProfile().StringTable(), keys, val)
		},
	}
}

func accessStringTable[K ProfileContext]() ottl.StandardGetSetter[K] {
	return ottl.StandardGetSetter[K]{
		Getter: func(_ context.Context, tCtx K) (any, error) {
			return tCtx.GetProfile().StringTable().AsRaw(), nil
		},
		Setter: func(_ context.Context, tCtx K, val any) error {
			return ctxutil.SetCommonTypedSliceValues[string](tCtx.GetProfile().StringTable(), val)
		},
	}
}

// *Int* function versions also handle type conversions and ensure returned values are compatible with OTTL defaults (int64).
// tCtx.GetProfile().LocationIndices() -> pcommon.Int32Slice
func accessLocationIndicesKey[K ProfileContext](ctx context.Context, keys []ottl.Key[K]) ottl.StandardGetSetter[K] {
	return ottl.StandardGetSetter[K]{
		Getter: func(_ context.Context, tCtx K) (any, error) {
			return ctxutil.GetCommonIntSliceValue[K, int32](ctx, tCtx, tCtx.GetProfile().LocationIndices(), keys)
		},
		Setter: func(_ context.Context, tCtx K, val any) error {
			return ctxutil.SetCommonIntSliceValue[K, int32](ctx, tCtx, tCtx.GetProfile().LocationIndices(), keys, val)
		},
	}
}

func accessLocationIndices[K ProfileContext]() ottl.StandardGetSetter[K] {
	return ottl.StandardGetSetter[K]{
		Getter: func(_ context.Context, tCtx K) (any, error) {
			return ctxutil.GetCommonIntSliceValues[int32](tCtx.GetProfile().LocationIndices()), nil
		},
		Setter: func(_ context.Context, tCtx K, val any) error {
			return ctxutil.SetCommonIntSliceValues[int32](tCtx.GetProfile().LocationIndices(), val)
		},
	}
}

Testing

  • Unit tests

@edmocosta edmocosta marked this pull request as ready for review March 24, 2025 22:30
@edmocosta edmocosta requested a review from a team as a code owner March 24, 2025 22:30
@edmocosta
Copy link
Contributor Author

@TylerHelmuth @evan-bradley @djaglowski could you please review? Those functions would be especially useful for the profile context #37574. Thanks.

@TylerHelmuth TylerHelmuth merged commit 862992b into open-telemetry:main Apr 10, 2025
171 checks passed
@github-actions github-actions bot added this to the next release milestone Apr 10, 2025
akshays-19 pushed a commit to akshays-19/opentelemetry-collector-contrib that referenced this pull request Apr 23, 2025
…ssors (open-telemetry#38928)

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

Currently, OTTL contexts setters can received different data type when
using slices, which might lead to unexpected outcomes, for example,
slice setters functions can receive the following value types:

-  `[]any` when set from literals: `set(string_table, ["foo", "bar"])`
    -   integer values within the `[]any` are parsed as `int64`
-  `[]T` when copied from another path: `set(slice_path, slice_path)`
- `pcommon.Slice` when set from an map's key value: `set(slice_path,
resource.attributes["slice"])`

Those different possibilities must be properly handled on the setter
assessors, and are not obvious since the value is any-wrapped. Failing
to handle all those possible types results in the path not being set or
errors.

This PR adds a set of functions that helps setting and getting slices
values, making it easier handling them until OTTL slice parsing is not
standardized. Those functions will be especially useful for the new
profile context
(open-telemetry#37574),
which needs to provide access to different pdata typed slices.

We've recently done something similar to maps
(open-telemetry#38434).

Usage examples:

```go
// tCtx.GetProfile().StringTable() -> pcommon.StringSlice
func accessStringTableKey[K ProfileContext](ctx context.Context, keys []ottl.Key[K]) ottl.StandardGetSetter[K] {
	return ottl.StandardGetSetter[K]{
		Getter: func(_ context.Context, tCtx K) (any, error) {
			return ctxutil.GetCommonTypedSliceValue[K, string](ctx, tCtx, tCtx.GetProfile().StringTable(), keys)
		},
		Setter: func(_ context.Context, tCtx K, val any) error {
			return ctxutil.SetCommonTypedSliceValue[K, string](ctx, tCtx, tCtx.GetProfile().StringTable(), keys, val)
		},
	}
}

func accessStringTable[K ProfileContext]() ottl.StandardGetSetter[K] {
	return ottl.StandardGetSetter[K]{
		Getter: func(_ context.Context, tCtx K) (any, error) {
			return tCtx.GetProfile().StringTable().AsRaw(), nil
		},
		Setter: func(_ context.Context, tCtx K, val any) error {
			return ctxutil.SetCommonTypedSliceValues[string](tCtx.GetProfile().StringTable(), val)
		},
	}
}

// *Int* function versions also handle type conversions and ensure returned values are compatible with OTTL defaults (int64).
// tCtx.GetProfile().LocationIndices() -> pcommon.Int32Slice
func accessLocationIndicesKey[K ProfileContext](ctx context.Context, keys []ottl.Key[K]) ottl.StandardGetSetter[K] {
	return ottl.StandardGetSetter[K]{
		Getter: func(_ context.Context, tCtx K) (any, error) {
			return ctxutil.GetCommonIntSliceValue[K, int32](ctx, tCtx, tCtx.GetProfile().LocationIndices(), keys)
		},
		Setter: func(_ context.Context, tCtx K, val any) error {
			return ctxutil.SetCommonIntSliceValue[K, int32](ctx, tCtx, tCtx.GetProfile().LocationIndices(), keys, val)
		},
	}
}

func accessLocationIndices[K ProfileContext]() ottl.StandardGetSetter[K] {
	return ottl.StandardGetSetter[K]{
		Getter: func(_ context.Context, tCtx K) (any, error) {
			return ctxutil.GetCommonIntSliceValues[int32](tCtx.GetProfile().LocationIndices()), nil
		},
		Setter: func(_ context.Context, tCtx K, val any) error {
			return ctxutil.SetCommonIntSliceValues[int32](tCtx.GetProfile().LocationIndices(), val)
		},
	}
}
```

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

<!--Please delete paragraphs that you did not use before submitting.-->

---------

Co-authored-by: Tim Rühsen <[email protected]>
Fiery-Fenix pushed a commit to Fiery-Fenix/opentelemetry-collector-contrib that referenced this pull request Apr 24, 2025
…ssors (open-telemetry#38928)

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

Currently, OTTL contexts setters can received different data type when
using slices, which might lead to unexpected outcomes, for example,
slice setters functions can receive the following value types:

-  `[]any` when set from literals: `set(string_table, ["foo", "bar"])`
    -   integer values within the `[]any` are parsed as `int64`
-  `[]T` when copied from another path: `set(slice_path, slice_path)`
- `pcommon.Slice` when set from an map's key value: `set(slice_path,
resource.attributes["slice"])`

Those different possibilities must be properly handled on the setter
assessors, and are not obvious since the value is any-wrapped. Failing
to handle all those possible types results in the path not being set or
errors.

This PR adds a set of functions that helps setting and getting slices
values, making it easier handling them until OTTL slice parsing is not
standardized. Those functions will be especially useful for the new
profile context
(open-telemetry#37574),
which needs to provide access to different pdata typed slices.

We've recently done something similar to maps
(open-telemetry#38434).

Usage examples:

```go
// tCtx.GetProfile().StringTable() -> pcommon.StringSlice
func accessStringTableKey[K ProfileContext](ctx context.Context, keys []ottl.Key[K]) ottl.StandardGetSetter[K] {
	return ottl.StandardGetSetter[K]{
		Getter: func(_ context.Context, tCtx K) (any, error) {
			return ctxutil.GetCommonTypedSliceValue[K, string](ctx, tCtx, tCtx.GetProfile().StringTable(), keys)
		},
		Setter: func(_ context.Context, tCtx K, val any) error {
			return ctxutil.SetCommonTypedSliceValue[K, string](ctx, tCtx, tCtx.GetProfile().StringTable(), keys, val)
		},
	}
}

func accessStringTable[K ProfileContext]() ottl.StandardGetSetter[K] {
	return ottl.StandardGetSetter[K]{
		Getter: func(_ context.Context, tCtx K) (any, error) {
			return tCtx.GetProfile().StringTable().AsRaw(), nil
		},
		Setter: func(_ context.Context, tCtx K, val any) error {
			return ctxutil.SetCommonTypedSliceValues[string](tCtx.GetProfile().StringTable(), val)
		},
	}
}

// *Int* function versions also handle type conversions and ensure returned values are compatible with OTTL defaults (int64).
// tCtx.GetProfile().LocationIndices() -> pcommon.Int32Slice
func accessLocationIndicesKey[K ProfileContext](ctx context.Context, keys []ottl.Key[K]) ottl.StandardGetSetter[K] {
	return ottl.StandardGetSetter[K]{
		Getter: func(_ context.Context, tCtx K) (any, error) {
			return ctxutil.GetCommonIntSliceValue[K, int32](ctx, tCtx, tCtx.GetProfile().LocationIndices(), keys)
		},
		Setter: func(_ context.Context, tCtx K, val any) error {
			return ctxutil.SetCommonIntSliceValue[K, int32](ctx, tCtx, tCtx.GetProfile().LocationIndices(), keys, val)
		},
	}
}

func accessLocationIndices[K ProfileContext]() ottl.StandardGetSetter[K] {
	return ottl.StandardGetSetter[K]{
		Getter: func(_ context.Context, tCtx K) (any, error) {
			return ctxutil.GetCommonIntSliceValues[int32](tCtx.GetProfile().LocationIndices()), nil
		},
		Setter: func(_ context.Context, tCtx K, val any) error {
			return ctxutil.SetCommonIntSliceValues[int32](tCtx.GetProfile().LocationIndices(), val)
		},
	}
}
```

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

<!--Please delete paragraphs that you did not use before submitting.-->

---------

Co-authored-by: Tim Rühsen <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants