From 85fc2d72b4a12735863755abcbd58bfe9a2a75d8 Mon Sep 17 00:00:00 2001 From: Florian Bacher Date: Wed, 8 Jan 2025 12:33:04 +0100 Subject: [PATCH 01/15] add event_index to available paths in span event context Signed-off-by: Florian Bacher --- .chloggen/ottl-span-event-index.yaml | 27 +++++++++++++ pkg/ottl/contexts/ottlspanevent/README.md | 39 ++++++++++--------- .../contexts/ottlspanevent/span_events.go | 32 +++++++++++++++ .../ottlspanevent/span_events_test.go | 19 +++++++-- 4 files changed, 94 insertions(+), 23 deletions(-) create mode 100644 .chloggen/ottl-span-event-index.yaml diff --git a/.chloggen/ottl-span-event-index.yaml b/.chloggen/ottl-span-event-index.yaml new file mode 100644 index 0000000000000..b36765ea0fcd1 --- /dev/null +++ b/.chloggen/ottl-span-event-index.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 `event_index` to the available paths of the span event context + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [35778] + +# (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: [] diff --git a/pkg/ottl/contexts/ottlspanevent/README.md b/pkg/ottl/contexts/ottlspanevent/README.md index 0de4ddb187745..95194ed779dcb 100644 --- a/pkg/ottl/contexts/ottlspanevent/README.md +++ b/pkg/ottl/contexts/ottlspanevent/README.md @@ -7,26 +7,27 @@ In general, the Span Event Context supports accessing pdata using the field name The following paths are supported. -| path | field accessed | type | -|----------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------| -| cache | the value of the current transform context's temporary cache. cache can be used as a temporary placeholder for data during complex transformations | pcommon.Map | -| cache\[""\] | the value of an item in cache. Supports multiple indexes to access nested fields. | string, bool, int64, float64, pcommon.Map, pcommon.Slice, []byte or nil | -| resource | resource of the span event being processed | pcommon.Resource | -| resource.attributes | resource attributes of the span event being processed | pcommon.Map | -| resource.attributes\[""\] | the value of the resource attribute of the span event being processed. Supports multiple indexes to access nested fields. | string, bool, int64, float64, pcommon.Map, pcommon.Slice, []byte or nil | -| instrumentation_scope | instrumentation scope of the span event being processed | pcommon.InstrumentationScope | -| instrumentation_scope.name | name of the instrumentation scope of the span event being processed | string | -| instrumentation_scope.version | version of the instrumentation scope of the span event being processed | string | -| instrumentation_scope.attributes | instrumentation scope attributes of the span event being processed | pcommon.Map | -| instrumentation_scope.attributes\[""\] | the value of the instrumentation scope attribute of the span event being processed. Supports multiple indexes to access nested fields. | string, bool, int64, float64, pcommon.Map, pcommon.Slice, []byte or nil | -| span | span of the span event being processed | ptrace.Span | +| path | field accessed | type | +|----------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------| +| cache | the value of the current transform context's temporary cache. cache can be used as a temporary placeholder for data during complex transformations | pcommon.Map | +| cache\[""\] | the value of an item in cache. Supports multiple indexes to access nested fields. | string, bool, int64, float64, pcommon.Map, pcommon.Slice, []byte or nil | +| resource | resource of the span event being processed | pcommon.Resource | +| resource.attributes | resource attributes of the span event being processed | pcommon.Map | +| resource.attributes\[""\] | the value of the resource attribute of the span event being processed. Supports multiple indexes to access nested fields. | string, bool, int64, float64, pcommon.Map, pcommon.Slice, []byte or nil | +| instrumentation_scope | instrumentation scope of the span event being processed | pcommon.InstrumentationScope | +| instrumentation_scope.name | name of the instrumentation scope of the span event being processed | string | +| instrumentation_scope.version | version of the instrumentation scope of the span event being processed | string | +| instrumentation_scope.attributes | instrumentation scope attributes of the span event being processed | pcommon.Map | +| instrumentation_scope.attributes\[""\] | the value of the instrumentation scope attribute of the span event being processed. Supports multiple indexes to access nested fields. | string, bool, int64, float64, pcommon.Map, pcommon.Slice, []byte or nil | +| span | span of the span event being processed | ptrace.Span | | span.* | All fields exposed by the [ottlspan context](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/pkg/ottl/contexts/ottlspan) can accessed via `span.` | varies | -| attributes | attributes of the span event being processed | pcommon.Map | -| attributes\[""\] | the value of the attribute of the span event being processed. Supports multiple indexes to access nested fields. | string, bool, int64, float64, pcommon.Map, pcommon.Slice, []byte or nil | -| time_unix_nano | time_unix_nano of the span event being processed | int64 | -| time | time of the span event being processed | `time.Time` | -| name | name of the span event being processed | string | -| dropped_attributes_count | dropped_attributes_count of the span event being processed | int64 | +| attributes | attributes of the span event being processed | pcommon.Map | +| attributes\[""\] | the value of the attribute of the span event being processed. Supports multiple indexes to access nested fields. | string, bool, int64, float64, pcommon.Map, pcommon.Slice, []byte or nil | +| time_unix_nano | time_unix_nano of the span event being processed | int64 | +| time | time of the span event being processed | `time.Time` | +| name | name of the span event being processed | string | +| dropped_attributes_count | dropped_attributes_count of the span event being processed | int64 | +| event_index | index of the span event within the span | int64 | ## Enums diff --git a/pkg/ottl/contexts/ottlspanevent/span_events.go b/pkg/ottl/contexts/ottlspanevent/span_events.go index 6d654b0580041..49de1448c3871 100644 --- a/pkg/ottl/contexts/ottlspanevent/span_events.go +++ b/pkg/ottl/contexts/ottlspanevent/span_events.go @@ -39,6 +39,7 @@ type TransformContext struct { cache pcommon.Map scopeSpans ptrace.ScopeSpans resouceSpans ptrace.ResourceSpans + eventIndex int64 } func (tCtx TransformContext) MarshalLogObject(encoder zapcore.ObjectEncoder) error { @@ -47,12 +48,21 @@ func (tCtx TransformContext) MarshalLogObject(encoder zapcore.ObjectEncoder) err err = errors.Join(err, encoder.AddObject("span", logging.Span(tCtx.span))) err = errors.Join(err, encoder.AddObject("spanevent", logging.SpanEvent(tCtx.spanEvent))) err = errors.Join(err, encoder.AddObject("cache", logging.Map(tCtx.cache))) + encoder.AddInt64("eventindex", tCtx.eventIndex) return err } type Option func(*ottl.Parser[TransformContext]) func NewTransformContext(spanEvent ptrace.SpanEvent, span ptrace.Span, instrumentationScope pcommon.InstrumentationScope, resource pcommon.Resource, scopeSpans ptrace.ScopeSpans, resourceSpans ptrace.ResourceSpans) TransformContext { + // calculate the event index + index := -1 + for i := 0; i < span.Events().Len(); i++ { + if span.Events().At(i) == spanEvent { + index = i + break + } + } return TransformContext{ spanEvent: spanEvent, span: span, @@ -61,6 +71,7 @@ func NewTransformContext(spanEvent ptrace.SpanEvent, span ptrace.Span, instrumen cache: pcommon.NewMap(), scopeSpans: scopeSpans, resouceSpans: resourceSpans, + eventIndex: int64(index), } } @@ -92,6 +103,10 @@ func (tCtx TransformContext) GetResourceSchemaURLItem() internal.SchemaURLItem { return tCtx.resouceSpans } +func (tCtx TransformContext) GetEventIndex() int64 { + return tCtx.eventIndex +} + func NewParser(functions map[string]ottl.Factory[TransformContext], telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) { pep := pathExpressionParser{telemetrySettings} p, err := ottl.NewParser[TransformContext]( @@ -206,6 +221,8 @@ func (pep *pathExpressionParser) parsePath(path ottl.Path[TransformContext]) (ot return accessSpanEventAttributesKey(path.Keys()), nil case "dropped_attributes_count": return accessSpanEventDroppedAttributeCount(), nil + case "event_index": + return accessSpanEventIndex(), nil default: return nil, internal.FormatDefaultErrorMessage(path.Name(), path.String(), contextNameDescription, internal.SpanEventRef) } @@ -333,3 +350,18 @@ func accessSpanEventDroppedAttributeCount() ottl.StandardGetSetter[TransformCont }, } } + +func accessSpanEventIndex() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(ctx context.Context, tCtx TransformContext) (any, error) { + return tCtx.eventIndex, nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + if newIndex, ok := val.(int64); ok { + tCtx.eventIndex = newIndex + } + return nil + }, + } + +} diff --git a/pkg/ottl/contexts/ottlspanevent/span_events_test.go b/pkg/ottl/contexts/ottlspanevent/span_events_test.go index 29abc6abce1d5..a599ba7936819 100644 --- a/pkg/ottl/contexts/ottlspanevent/span_events_test.go +++ b/pkg/ottl/contexts/ottlspanevent/span_events_test.go @@ -407,6 +407,16 @@ func Test_newPathGetSetter(t *testing.T) { spanEvent.SetDroppedAttributesCount(20) }, }, + { + name: "event_index", + path: &internal.TestPath[TransformContext]{ + N: "event_index", + }, + orig: int64(0), + newVal: int64(1), + modified: func(spanEvent ptrace.SpanEvent, _ ptrace.Span, _ pcommon.InstrumentationScope, _ pcommon.Resource, _ pcommon.Map) { + }, + }, } // Copy all tests cases and sets the path.Context value to the generated ones. // It ensures all exiting field access also work when the path context is set. @@ -521,7 +531,11 @@ func Test_newPathGetSetter_higherContextPath(t *testing.T) { } func createTelemetry() (ptrace.SpanEvent, ptrace.Span, pcommon.InstrumentationScope, pcommon.Resource) { - spanEvent := ptrace.NewSpanEvent() + + span := ptrace.NewSpan() + span.SetName("test") + + spanEvent := span.Events().AppendEmpty() spanEvent.SetName("bear") spanEvent.SetTimestamp(pcommon.NewTimestampFromTime(time.UnixMilli(100))) @@ -562,9 +576,6 @@ func createTelemetry() (ptrace.SpanEvent, ptrace.Span, pcommon.InstrumentationSc s := spanEvent.Attributes().PutEmptySlice("slice") s.AppendEmpty().SetEmptyMap().PutStr("map", "pass") - span := ptrace.NewSpan() - span.SetName("test") - il := pcommon.NewInstrumentationScope() il.SetName("library") il.SetVersion("version") From c44e5129e521faed7c36a13dfcb1fb11073d7c6c Mon Sep 17 00:00:00 2001 From: Florian Bacher Date: Wed, 8 Jan 2025 13:06:41 +0100 Subject: [PATCH 02/15] make event index only readable, fix linting Signed-off-by: Florian Bacher --- pkg/ottl/contexts/ottlspanevent/span_events.go | 8 ++------ pkg/ottl/contexts/ottlspanevent/span_events_test.go | 3 +-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/pkg/ottl/contexts/ottlspanevent/span_events.go b/pkg/ottl/contexts/ottlspanevent/span_events.go index 49de1448c3871..69fea44c69682 100644 --- a/pkg/ottl/contexts/ottlspanevent/span_events.go +++ b/pkg/ottl/contexts/ottlspanevent/span_events.go @@ -353,15 +353,11 @@ func accessSpanEventDroppedAttributeCount() ottl.StandardGetSetter[TransformCont func accessSpanEventIndex() ottl.StandardGetSetter[TransformContext] { return ottl.StandardGetSetter[TransformContext]{ - Getter: func(ctx context.Context, tCtx TransformContext) (any, error) { + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { return tCtx.eventIndex, nil }, - Setter: func(_ context.Context, tCtx TransformContext, val any) error { - if newIndex, ok := val.(int64); ok { - tCtx.eventIndex = newIndex - } + Setter: func(_ context.Context, _ TransformContext, _ any) error { return nil }, } - } diff --git a/pkg/ottl/contexts/ottlspanevent/span_events_test.go b/pkg/ottl/contexts/ottlspanevent/span_events_test.go index a599ba7936819..3745f7a7a472d 100644 --- a/pkg/ottl/contexts/ottlspanevent/span_events_test.go +++ b/pkg/ottl/contexts/ottlspanevent/span_events_test.go @@ -414,7 +414,7 @@ func Test_newPathGetSetter(t *testing.T) { }, orig: int64(0), newVal: int64(1), - modified: func(spanEvent ptrace.SpanEvent, _ ptrace.Span, _ pcommon.InstrumentationScope, _ pcommon.Resource, _ pcommon.Map) { + modified: func(_ ptrace.SpanEvent, _ ptrace.Span, _ pcommon.InstrumentationScope, _ pcommon.Resource, _ pcommon.Map) { }, }, } @@ -531,7 +531,6 @@ func Test_newPathGetSetter_higherContextPath(t *testing.T) { } func createTelemetry() (ptrace.SpanEvent, ptrace.Span, pcommon.InstrumentationScope, pcommon.Resource) { - span := ptrace.NewSpan() span.SetName("test") From bd05a002740c19972d2687abdcf5aee80d53dc9f Mon Sep 17 00:00:00 2001 From: Florian Bacher Date: Thu, 9 Jan 2025 13:07:42 +0100 Subject: [PATCH 03/15] add e2e test Signed-off-by: Florian Bacher --- pkg/ottl/e2e/e2e_test.go | 56 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/pkg/ottl/e2e/e2e_test.go b/pkg/ottl/e2e/e2e_test.go index 72077e66dd230..95d93ca005752 100644 --- a/pkg/ottl/e2e/e2e_test.go +++ b/pkg/ottl/e2e/e2e_test.go @@ -5,6 +5,7 @@ package e2e import ( "context" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlspanevent" "net/http" "testing" "time" @@ -1122,6 +1123,40 @@ func Test_ProcessTraces_TraceContext(t *testing.T) { } } +func Test_ProcessSpanEvents(t *testing.T) { + tests := []struct { + statement string + want func(_ ottlspanevent.TransformContext) + }{ + { + statement: `set(attributes["index"], event_index)`, + want: func(tCtx ottlspanevent.TransformContext) { + tCtx.GetSpanEvent().Attributes().PutInt("index", 0) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.statement, func(t *testing.T) { + settings := componenttest.NewNopTelemetrySettings() + funcs := ottlfuncs.StandardFuncs[ottlspanevent.TransformContext]() + + spanEventParser, err := ottlspanevent.NewParser(funcs, settings) + assert.NoError(t, err) + spanStatements, err := spanEventParser.ParseStatement(tt.statement) + assert.NoError(t, err) + + tCtx := constructSpanEventTransformContext() + _, _, _ = spanStatements.Execute(context.Background(), tCtx) + + exTCtx := constructSpanEventTransformContext() + tt.want(exTCtx) + + assert.NoError(t, ptracetest.CompareSpanEvent(newSpanEvent(exTCtx), newSpanEvent(tCtx))) + }) + } +} + func constructLogTransformContext() ottllog.TransformContext { resource := pcommon.NewResource() resource.Attributes().PutStr("host.name", "localhost") @@ -1176,6 +1211,21 @@ func constructSpanTransformContext() ottlspan.TransformContext { return ottlspan.NewTransformContext(td, scope, resource, ptrace.NewScopeSpans(), ptrace.NewResourceSpans()) } +func constructSpanEventTransformContext() ottlspanevent.TransformContext { + resource := pcommon.NewResource() + + scope := pcommon.NewInstrumentationScope() + scope.SetName("scope") + + span := ptrace.NewSpan() + fillSpanOne(span) + + ev1 := span.Events().AppendEmpty() + ev1.SetName("event-1") + + return ottlspanevent.NewTransformContext(ev1, span, scope, resource, ptrace.NewScopeSpans(), ptrace.NewResourceSpans()) +} + func newResourceLogs(tCtx ottllog.TransformContext) plog.ResourceLogs { rl := plog.NewResourceLogs() tCtx.GetResource().CopyTo(rl.Resource()) @@ -1196,6 +1246,12 @@ func newResourceSpans(tCtx ottlspan.TransformContext) ptrace.ResourceSpans { return rl } +func newSpanEvent(tCtx ottlspanevent.TransformContext) ptrace.SpanEvent { + dst := ptrace.NewSpanEvent() + tCtx.GetSpanEvent().CopyTo(dst) + return dst +} + func fillSpanOne(span ptrace.Span) { span.SetName("operationB") span.SetSpanID(spanID) From 9be8cbf42f434e33f5d36d9bc2b337a2e757a66e Mon Sep 17 00:00:00 2001 From: Florian Bacher Date: Thu, 9 Jan 2025 13:16:06 +0100 Subject: [PATCH 04/15] fix linting Signed-off-by: Florian Bacher --- pkg/ottl/e2e/e2e_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/ottl/e2e/e2e_test.go b/pkg/ottl/e2e/e2e_test.go index 95d93ca005752..b30b188788225 100644 --- a/pkg/ottl/e2e/e2e_test.go +++ b/pkg/ottl/e2e/e2e_test.go @@ -5,7 +5,6 @@ package e2e import ( "context" - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlspanevent" "net/http" "testing" "time" @@ -18,6 +17,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottllog" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlspan" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlspanevent" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/plogtest" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/ptracetest" From 98bb6c644bad71e609af32f0c4628cf37b2963b1 Mon Sep 17 00:00:00 2001 From: Florian Bacher Date: Fri, 10 Jan 2025 06:59:30 +0100 Subject: [PATCH 05/15] Update pkg/ottl/contexts/ottlspanevent/span_events.go Co-authored-by: Evan Bradley <11745660+evan-bradley@users.noreply.github.com> --- pkg/ottl/contexts/ottlspanevent/span_events.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/ottl/contexts/ottlspanevent/span_events.go b/pkg/ottl/contexts/ottlspanevent/span_events.go index 69fea44c69682..a9f41b1c60ea5 100644 --- a/pkg/ottl/contexts/ottlspanevent/span_events.go +++ b/pkg/ottl/contexts/ottlspanevent/span_events.go @@ -357,7 +357,7 @@ func accessSpanEventIndex() ottl.StandardGetSetter[TransformContext] { return tCtx.eventIndex, nil }, Setter: func(_ context.Context, _ TransformContext, _ any) error { - return nil + return errors.New("the 'event_index' path cannot be modified") }, } } From edc288caa03c353461dd177c17539a5135984ed9 Mon Sep 17 00:00:00 2001 From: Florian Bacher Date: Mon, 13 Jan 2025 14:39:04 +0100 Subject: [PATCH 06/15] fix failing unit test Signed-off-by: Florian Bacher --- .../ottlspanevent/span_events_test.go | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/pkg/ottl/contexts/ottlspanevent/span_events_test.go b/pkg/ottl/contexts/ottlspanevent/span_events_test.go index 3745f7a7a472d..6a67c049ebbab 100644 --- a/pkg/ottl/contexts/ottlspanevent/span_events_test.go +++ b/pkg/ottl/contexts/ottlspanevent/span_events_test.go @@ -49,11 +49,12 @@ func Test_newPathGetSetter(t *testing.T) { newMap["k2"] = newMap2 tests := []struct { - name string - path ottl.Path[TransformContext] - orig any - newVal any - modified func(spanEvent ptrace.SpanEvent, span ptrace.Span, il pcommon.InstrumentationScope, resource pcommon.Resource, cache pcommon.Map) + name string + path ottl.Path[TransformContext] + orig any + newVal any + expectSetterError bool + modified func(spanEvent ptrace.SpanEvent, span ptrace.Span, il pcommon.InstrumentationScope, resource pcommon.Resource, cache pcommon.Map) }{ { name: "span event time", @@ -412,10 +413,9 @@ func Test_newPathGetSetter(t *testing.T) { path: &internal.TestPath[TransformContext]{ N: "event_index", }, - orig: int64(0), - newVal: int64(1), - modified: func(_ ptrace.SpanEvent, _ ptrace.Span, _ pcommon.InstrumentationScope, _ pcommon.Resource, _ pcommon.Map) { - }, + orig: int64(0), + newVal: int64(1), + expectSetterError: true, }, } // Copy all tests cases and sets the path.Context value to the generated ones. @@ -443,6 +443,10 @@ func Test_newPathGetSetter(t *testing.T) { assert.Equal(t, tt.orig, got) err = accessor.Set(context.Background(), tCtx, tt.newVal) + if tt.expectSetterError { + assert.Error(t, err) + return + } assert.NoError(t, err) exSpanEvent, exSpan, exIl, exRes := createTelemetry() From f2189e17f0e385438bd345cb5e7087e12962e361 Mon Sep 17 00:00:00 2001 From: Florian Bacher Date: Fri, 17 Jan 2025 10:17:13 +0100 Subject: [PATCH 07/15] add license header Signed-off-by: Florian Bacher --- pkg/ottl/contexts/ottlspanevent/span_events.go | 17 ++++++++--------- .../contexts/ottlspanevent/span_events_test.go | 4 ++-- .../internal/sampling/ottl.go | 2 +- .../internal/common/traces.go | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/pkg/ottl/contexts/ottlspanevent/span_events.go b/pkg/ottl/contexts/ottlspanevent/span_events.go index 1944451e39f37..c9d4175e240c1 100644 --- a/pkg/ottl/contexts/ottlspanevent/span_events.go +++ b/pkg/ottl/contexts/ottlspanevent/span_events.go @@ -57,14 +57,6 @@ type Option func(*ottl.Parser[TransformContext]) type TransformContextOption func(*TransformContext) func NewTransformContext(spanEvent ptrace.SpanEvent, span ptrace.Span, instrumentationScope pcommon.InstrumentationScope, resource pcommon.Resource, scopeSpans ptrace.ScopeSpans, resourceSpans ptrace.ResourceSpans, options ...TransformContextOption) TransformContext { - // calculate the event index - index := -1 - for i := 0; i < span.Events().Len(); i++ { - if span.Events().At(i) == spanEvent { - index = i - break - } - } tc := TransformContext{ spanEvent: spanEvent, span: span, @@ -73,7 +65,6 @@ func NewTransformContext(spanEvent ptrace.SpanEvent, span ptrace.Span, instrumen cache: pcommon.NewMap(), scopeSpans: scopeSpans, resouceSpans: resourceSpans, - eventIndex: int64(index), } for _, opt := range options { opt(&tc) @@ -90,6 +81,14 @@ func WithCache(cache *pcommon.Map) TransformContextOption { } } +func WithEventIndex(eventIndex int64) TransformContextOption { + return func(p *TransformContext) { + if eventIndex >= 0 { + p.eventIndex = eventIndex + } + } +} + func (tCtx TransformContext) GetSpanEvent() ptrace.SpanEvent { return tCtx.spanEvent } diff --git a/pkg/ottl/contexts/ottlspanevent/span_events_test.go b/pkg/ottl/contexts/ottlspanevent/span_events_test.go index 6a67c049ebbab..ecfccb7664c79 100644 --- a/pkg/ottl/contexts/ottlspanevent/span_events_test.go +++ b/pkg/ottl/contexts/ottlspanevent/span_events_test.go @@ -413,7 +413,7 @@ func Test_newPathGetSetter(t *testing.T) { path: &internal.TestPath[TransformContext]{ N: "event_index", }, - orig: int64(0), + orig: int64(1), newVal: int64(1), expectSetterError: true, }, @@ -436,7 +436,7 @@ func Test_newPathGetSetter(t *testing.T) { spanEvent, span, il, resource := createTelemetry() - tCtx := NewTransformContext(spanEvent, span, il, resource, ptrace.NewScopeSpans(), ptrace.NewResourceSpans()) + tCtx := NewTransformContext(spanEvent, span, il, resource, ptrace.NewScopeSpans(), ptrace.NewResourceSpans(), WithEventIndex(1)) got, err := accessor.Get(context.Background(), tCtx) assert.NoError(t, err) diff --git a/processor/tailsamplingprocessor/internal/sampling/ottl.go b/processor/tailsamplingprocessor/internal/sampling/ottl.go index 7d5f520ece503..0913c6c70d086 100644 --- a/processor/tailsamplingprocessor/internal/sampling/ottl.go +++ b/processor/tailsamplingprocessor/internal/sampling/ottl.go @@ -100,7 +100,7 @@ func (ocf *ottlConditionFilter) Evaluate(ctx context.Context, traceID pcommon.Tr if ocf.sampleSpanEventExpr != nil { spanEvents := span.Events() for l := 0; l < spanEvents.Len(); l++ { - ok, err = ocf.sampleSpanEventExpr.Eval(ctx, ottlspanevent.NewTransformContext(spanEvents.At(l), span, scope, resource, ss, rs)) + ok, err = ocf.sampleSpanEventExpr.Eval(ctx, ottlspanevent.NewTransformContext(spanEvents.At(l), span, scope, resource, ss, rs, ottlspanevent.WithEventIndex(int64(l)))) if err != nil { return Error, err } diff --git a/processor/transformprocessor/internal/common/traces.go b/processor/transformprocessor/internal/common/traces.go index de03b8afe9172..45a820fd6ea70 100644 --- a/processor/transformprocessor/internal/common/traces.go +++ b/processor/transformprocessor/internal/common/traces.go @@ -79,7 +79,7 @@ func (s spanEventStatements) ConsumeTraces(ctx context.Context, td ptrace.Traces span := spans.At(k) spanEvents := span.Events() for n := 0; n < spanEvents.Len(); n++ { - tCtx := ottlspanevent.NewTransformContext(spanEvents.At(n), span, sspans.Scope(), rspans.Resource(), sspans, rspans) + tCtx := ottlspanevent.NewTransformContext(spanEvents.At(n), span, sspans.Scope(), rspans.Resource(), sspans, rspans, ottlspanevent.WithEventIndex(int64(n))) condition, err := s.BoolExpr.Eval(ctx, tCtx) if err != nil { return err From 8a2c3b0ebc67282dc8d99fd27642d6c343427fd6 Mon Sep 17 00:00:00 2001 From: Florian Bacher Date: Mon, 20 Jan 2025 07:06:39 +0100 Subject: [PATCH 08/15] add godoc comment Signed-off-by: Florian Bacher --- pkg/ottl/contexts/ottlspanevent/span_events.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/ottl/contexts/ottlspanevent/span_events.go b/pkg/ottl/contexts/ottlspanevent/span_events.go index c9d4175e240c1..dc9ba845051f2 100644 --- a/pkg/ottl/contexts/ottlspanevent/span_events.go +++ b/pkg/ottl/contexts/ottlspanevent/span_events.go @@ -81,6 +81,8 @@ func WithCache(cache *pcommon.Map) TransformContextOption { } } +// WithEventIndex sets the index of the SpanEvent within the span, to make it accessible via the event_index property of its context. +// The index must be greater than or equal to zero, otherwise the given val will not be applied. func WithEventIndex(eventIndex int64) TransformContextOption { return func(p *TransformContext) { if eventIndex >= 0 { From 2f0fb0cd8b41d36c382801706cc7cfe69669a226 Mon Sep 17 00:00:00 2001 From: Florian Bacher Date: Mon, 20 Jan 2025 07:15:23 +0100 Subject: [PATCH 09/15] revert changes outside of ottl Signed-off-by: Florian Bacher --- processor/tailsamplingprocessor/internal/sampling/ottl.go | 2 +- processor/transformprocessor/internal/common/traces.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/processor/tailsamplingprocessor/internal/sampling/ottl.go b/processor/tailsamplingprocessor/internal/sampling/ottl.go index 0913c6c70d086..7d5f520ece503 100644 --- a/processor/tailsamplingprocessor/internal/sampling/ottl.go +++ b/processor/tailsamplingprocessor/internal/sampling/ottl.go @@ -100,7 +100,7 @@ func (ocf *ottlConditionFilter) Evaluate(ctx context.Context, traceID pcommon.Tr if ocf.sampleSpanEventExpr != nil { spanEvents := span.Events() for l := 0; l < spanEvents.Len(); l++ { - ok, err = ocf.sampleSpanEventExpr.Eval(ctx, ottlspanevent.NewTransformContext(spanEvents.At(l), span, scope, resource, ss, rs, ottlspanevent.WithEventIndex(int64(l)))) + ok, err = ocf.sampleSpanEventExpr.Eval(ctx, ottlspanevent.NewTransformContext(spanEvents.At(l), span, scope, resource, ss, rs)) if err != nil { return Error, err } diff --git a/processor/transformprocessor/internal/common/traces.go b/processor/transformprocessor/internal/common/traces.go index 45a820fd6ea70..de03b8afe9172 100644 --- a/processor/transformprocessor/internal/common/traces.go +++ b/processor/transformprocessor/internal/common/traces.go @@ -79,7 +79,7 @@ func (s spanEventStatements) ConsumeTraces(ctx context.Context, td ptrace.Traces span := spans.At(k) spanEvents := span.Events() for n := 0; n < spanEvents.Len(); n++ { - tCtx := ottlspanevent.NewTransformContext(spanEvents.At(n), span, sspans.Scope(), rspans.Resource(), sspans, rspans, ottlspanevent.WithEventIndex(int64(n))) + tCtx := ottlspanevent.NewTransformContext(spanEvents.At(n), span, sspans.Scope(), rspans.Resource(), sspans, rspans) condition, err := s.BoolExpr.Eval(ctx, tCtx) if err != nil { return err From db42306c444b243b9677da78d432d3158bd7942f Mon Sep 17 00:00:00 2001 From: Florian Bacher Date: Thu, 23 Jan 2025 08:24:14 +0100 Subject: [PATCH 10/15] adapt to PR review Signed-off-by: Florian Bacher --- .../contexts/ottlspanevent/span_events.go | 22 ++++--- .../ottlspanevent/span_events_test.go | 57 +++++++++++++++++++ pkg/ottl/e2e/e2e_test.go | 2 +- 3 files changed, 72 insertions(+), 9 deletions(-) diff --git a/pkg/ottl/contexts/ottlspanevent/span_events.go b/pkg/ottl/contexts/ottlspanevent/span_events.go index dc9ba845051f2..a2a0bf61f1874 100644 --- a/pkg/ottl/contexts/ottlspanevent/span_events.go +++ b/pkg/ottl/contexts/ottlspanevent/span_events.go @@ -39,7 +39,7 @@ type TransformContext struct { cache pcommon.Map scopeSpans ptrace.ScopeSpans resouceSpans ptrace.ResourceSpans - eventIndex int64 + eventIndex *int64 } func (tCtx TransformContext) MarshalLogObject(encoder zapcore.ObjectEncoder) error { @@ -48,7 +48,9 @@ func (tCtx TransformContext) MarshalLogObject(encoder zapcore.ObjectEncoder) err err = errors.Join(err, encoder.AddObject("span", logging.Span(tCtx.span))) err = errors.Join(err, encoder.AddObject("spanevent", logging.SpanEvent(tCtx.spanEvent))) err = errors.Join(err, encoder.AddObject("cache", logging.Map(tCtx.cache))) - encoder.AddInt64("eventindex", tCtx.eventIndex) + if tCtx.eventIndex != nil { + encoder.AddInt64("eventindex", *tCtx.eventIndex) + } return err } @@ -85,9 +87,7 @@ func WithCache(cache *pcommon.Map) TransformContextOption { // The index must be greater than or equal to zero, otherwise the given val will not be applied. func WithEventIndex(eventIndex int64) TransformContextOption { return func(p *TransformContext) { - if eventIndex >= 0 { - p.eventIndex = eventIndex - } + p.eventIndex = &eventIndex } } @@ -119,8 +119,14 @@ func (tCtx TransformContext) GetResourceSchemaURLItem() internal.SchemaURLItem { return tCtx.resouceSpans } -func (tCtx TransformContext) GetEventIndex() int64 { - return tCtx.eventIndex +func (tCtx TransformContext) GetEventIndex() (int64, error) { + if tCtx.eventIndex != nil { + if *tCtx.eventIndex < 0 { + return 0, errors.New("found invalid value for 'event_index'") + } + return *tCtx.eventIndex, nil + } + return 0, errors.New("no 'event_index' property has been set") } func NewParser(functions map[string]ottl.Factory[TransformContext], telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) { @@ -370,7 +376,7 @@ func accessSpanEventDroppedAttributeCount() ottl.StandardGetSetter[TransformCont func accessSpanEventIndex() ottl.StandardGetSetter[TransformContext] { return ottl.StandardGetSetter[TransformContext]{ Getter: func(_ context.Context, tCtx TransformContext) (any, error) { - return tCtx.eventIndex, nil + return tCtx.GetEventIndex() }, Setter: func(_ context.Context, _ TransformContext, _ any) error { return errors.New("the 'event_index' path cannot be modified") diff --git a/pkg/ottl/contexts/ottlspanevent/span_events_test.go b/pkg/ottl/contexts/ottlspanevent/span_events_test.go index ecfccb7664c79..a616a813c0327 100644 --- a/pkg/ottl/contexts/ottlspanevent/span_events_test.go +++ b/pkg/ottl/contexts/ottlspanevent/span_events_test.go @@ -534,6 +534,63 @@ func Test_newPathGetSetter_higherContextPath(t *testing.T) { } } +func Test_setAndGetEventIndex(t *testing.T) { + + tests := []struct { + name string + setEventIndex bool + eventIndexValue int64 + expected any + expectedErrorMsg string + }{ + { + name: "event index set", + setEventIndex: true, + eventIndexValue: 1, + expected: int64(1), + }, + { + name: "invalid value for event index", + setEventIndex: true, + eventIndexValue: -1, + expectedErrorMsg: "found invalid value for 'event_index'", + }, + { + name: "no value for event index", + setEventIndex: false, + expectedErrorMsg: "no 'event_index' property has been set", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + spanEvent, span, il, resource := createTelemetry() + + var tCtx TransformContext + if tt.setEventIndex { + tCtx = NewTransformContext(spanEvent, span, il, resource, ptrace.NewScopeSpans(), ptrace.NewResourceSpans(), WithEventIndex(tt.eventIndexValue)) + } else { + tCtx = NewTransformContext(spanEvent, span, il, resource, ptrace.NewScopeSpans(), ptrace.NewResourceSpans()) + } + + pep := pathExpressionParser{} + accessor, err := pep.parsePath(&internal.TestPath[TransformContext]{ + N: "event_index", + }) + assert.NoError(t, err) + + got, err := accessor.Get(context.Background(), tCtx) + if tt.expectedErrorMsg != "" { + assert.Error(t, err) + assert.ErrorContains(t, err, tt.expectedErrorMsg) + return + } + assert.NoError(t, err) + assert.Equal(t, tt.expected, got) + }) + } +} + func createTelemetry() (ptrace.SpanEvent, ptrace.Span, pcommon.InstrumentationScope, pcommon.Resource) { span := ptrace.NewSpan() span.SetName("test") diff --git a/pkg/ottl/e2e/e2e_test.go b/pkg/ottl/e2e/e2e_test.go index de8a4a4d88454..82659ba7e0dca 100644 --- a/pkg/ottl/e2e/e2e_test.go +++ b/pkg/ottl/e2e/e2e_test.go @@ -1428,7 +1428,7 @@ func constructSpanEventTransformContext() ottlspanevent.TransformContext { ev1 := span.Events().AppendEmpty() ev1.SetName("event-1") - return ottlspanevent.NewTransformContext(ev1, span, scope, resource, ptrace.NewScopeSpans(), ptrace.NewResourceSpans()) + return ottlspanevent.NewTransformContext(ev1, span, scope, resource, ptrace.NewScopeSpans(), ptrace.NewResourceSpans(), ottlspanevent.WithEventIndex(0)) } func newResourceLogs(tCtx ottllog.TransformContext) plog.ResourceLogs { From 771cd5c6448e854ff953a06fb908b1534a369328 Mon Sep 17 00:00:00 2001 From: Florian Bacher Date: Fri, 24 Jan 2025 07:13:43 +0100 Subject: [PATCH 11/15] fix linting Signed-off-by: Florian Bacher --- pkg/ottl/contexts/ottlspanevent/span_events_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/ottl/contexts/ottlspanevent/span_events_test.go b/pkg/ottl/contexts/ottlspanevent/span_events_test.go index a616a813c0327..9b8a7564de930 100644 --- a/pkg/ottl/contexts/ottlspanevent/span_events_test.go +++ b/pkg/ottl/contexts/ottlspanevent/span_events_test.go @@ -535,7 +535,6 @@ func Test_newPathGetSetter_higherContextPath(t *testing.T) { } func Test_setAndGetEventIndex(t *testing.T) { - tests := []struct { name string setEventIndex bool From f748203ff50e47a0f2a8b862cbdca3b0260b36e4 Mon Sep 17 00:00:00 2001 From: Florian Bacher Date: Wed, 19 Feb 2025 13:22:07 +0100 Subject: [PATCH 12/15] fix build errors Signed-off-by: Florian Bacher --- pkg/ottl/contexts/ottlspanevent/span_events_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/ottl/contexts/ottlspanevent/span_events_test.go b/pkg/ottl/contexts/ottlspanevent/span_events_test.go index 5321c2abe1c32..42ba50bb329f4 100644 --- a/pkg/ottl/contexts/ottlspanevent/span_events_test.go +++ b/pkg/ottl/contexts/ottlspanevent/span_events_test.go @@ -410,7 +410,7 @@ func Test_newPathGetSetter(t *testing.T) { }, { name: "event_index", - path: &internal.TestPath[TransformContext]{ + path: &pathtest.Path[TransformContext]{ N: "event_index", }, orig: int64(1), @@ -573,7 +573,7 @@ func Test_setAndGetEventIndex(t *testing.T) { } pep := pathExpressionParser{} - accessor, err := pep.parsePath(&internal.TestPath[TransformContext]{ + accessor, err := pep.parsePath(&pathtest.Path[TransformContext]{ N: "event_index", }) assert.NoError(t, err) From 3df1ea06f79fee288886fc786baebfb34cd7041e Mon Sep 17 00:00:00 2001 From: Florian Bacher Date: Thu, 20 Feb 2025 08:57:37 +0100 Subject: [PATCH 13/15] trigger CI Signed-off-by: Florian Bacher From 30369f43dd4c5e12f934372eae89919c3eec4014 Mon Sep 17 00:00:00 2001 From: Florian Bacher Date: Thu, 20 Feb 2025 16:56:49 +0100 Subject: [PATCH 14/15] trigger CI Signed-off-by: Florian Bacher From 0678726940c881f4c19c68bf5eb7d7f38d689777 Mon Sep 17 00:00:00 2001 From: Tyler Helmuth <12352919+TylerHelmuth@users.noreply.github.com> Date: Mon, 24 Feb 2025 08:18:34 -0700 Subject: [PATCH 15/15] Apply suggestions from code review Co-authored-by: Edmo Vamerlatti Costa <11836452+edmocosta@users.noreply.github.com> --- pkg/ottl/contexts/ottlspanevent/span_events.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/ottl/contexts/ottlspanevent/span_events.go b/pkg/ottl/contexts/ottlspanevent/span_events.go index a2a0bf61f1874..b251cc7b6e899 100644 --- a/pkg/ottl/contexts/ottlspanevent/span_events.go +++ b/pkg/ottl/contexts/ottlspanevent/span_events.go @@ -49,7 +49,7 @@ func (tCtx TransformContext) MarshalLogObject(encoder zapcore.ObjectEncoder) err err = errors.Join(err, encoder.AddObject("spanevent", logging.SpanEvent(tCtx.spanEvent))) err = errors.Join(err, encoder.AddObject("cache", logging.Map(tCtx.cache))) if tCtx.eventIndex != nil { - encoder.AddInt64("eventindex", *tCtx.eventIndex) + encoder.AddInt64("event_index", *tCtx.eventIndex) } return err }