Skip to content

[chore] Allow OTTL pdata Map setters to take raw map #38434

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

TylerHelmuth
Copy link
Member

Description

To be consistent, we should try treating raw maps and pcommon.Map the same. Updates all the setters that were expecting a pcommon.Map to also allow a raw map to set the value

Testing

unit tests

@edmocosta
Copy link
Contributor

edmocosta commented Mar 6, 2025

We could maybe add a new function into the internal/ctxutil package for handling this common logic, E.g.:

func SetMap(target pcommon.Map, val any) error {
	if cm, ok := val.(pcommon.Map); ok {
		cm.CopyTo(target)
		return nil
	}
	if rm, ok := val.(map[string]any); ok {
		return target.FromRaw(rm)
	}
	return nil
}

@TylerHelmuth TylerHelmuth merged commit 14de63f into open-telemetry:main Mar 6, 2025
156 checks passed
@github-actions github-actions bot added this to the next release milestone Mar 6, 2025
TylerHelmuth pushed a commit that referenced this pull request Apr 10, 2025
…ssors (#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
(#37574),
which needs to provide access to different pdata typed slices.

We've recently done something similar to maps
(#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 <tim.ruehsen@gmx.de>
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 <tim.ruehsen@gmx.de>
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 <tim.ruehsen@gmx.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants