diff --git a/cmd/query/app/querysvc/adjuster/adjuster.go b/cmd/query/app/querysvc/adjuster/adjuster.go index e6c4f4039fb..33b8de79d91 100644 --- a/cmd/query/app/querysvc/adjuster/adjuster.go +++ b/cmd/query/app/querysvc/adjuster/adjuster.go @@ -9,20 +9,12 @@ import ( "go.opentelemetry.io/collector/pdata/ptrace" ) -// Adjuster defines an interface for modifying a trace object. -// It returns the adjusted trace object, which is also updated in place. -// If the adjuster encounters an issue that prevents it from applying -// modifications, it should return the original trace object along with an error. +// Adjuster is an interface for modifying a trace object in place. +// If an issue is encountered that prevents modifications, an error should be returned. +// The caller must ensure that all spans in the ptrace.Traces argument +// belong to the same trace and represent the complete trace. type Adjuster interface { - Adjust(ptrace.Traces) (ptrace.Traces, error) -} - -// Func is a type alias that wraps a function and makes an Adjuster from it. -type Func func(traces ptrace.Traces) (ptrace.Traces, error) - -// Adjust implements Adjuster interface for the Func alias. -func (f Func) Adjust(traces ptrace.Traces) (ptrace.Traces, error) { - return f(traces) + Adjust(ptrace.Traces) error } // Sequence creates an adjuster that combines a series of adjusters @@ -44,17 +36,16 @@ type sequence struct { failFast bool } -func (c sequence) Adjust(traces ptrace.Traces) (ptrace.Traces, error) { +func (c sequence) Adjust(traces ptrace.Traces) error { var errs []error for _, adjuster := range c.adjusters { - var err error - traces, err = adjuster.Adjust(traces) + err := adjuster.Adjust(traces) if err != nil { if c.failFast { - return traces, err + return err } errs = append(errs, err) } } - return traces, errors.Join(errs...) + return errors.Join(errs...) } diff --git a/cmd/query/app/querysvc/adjuster/adjuster_test.go b/cmd/query/app/querysvc/adjuster/adjuster_test.go index 96cd4336988..fbc5804ed9e 100644 --- a/cmd/query/app/querysvc/adjuster/adjuster_test.go +++ b/cmd/query/app/querysvc/adjuster/adjuster_test.go @@ -4,7 +4,6 @@ package adjuster_test import ( - "errors" "fmt" "testing" @@ -16,21 +15,23 @@ import ( "github.com/jaegertracing/jaeger/cmd/query/app/querysvc/adjuster" ) -func TestSequences(t *testing.T) { - // mock adjuster that increments last byte of span ID - adj := adjuster.Func(func(trace ptrace.Traces) (ptrace.Traces, error) { - span := trace.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0) - spanId := span.SpanID() - spanId[7]++ - span.SetSpanID(spanId) - return trace, nil - }) +type mockAdjuster struct{} + +func (mockAdjuster) Adjust(traces ptrace.Traces) error { + span := traces.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0) + spanId := span.SpanID() + spanId[7]++ + span.SetSpanID(spanId) + return nil +} + +type mockAdjusterError struct{} - adjErr := errors.New("mock adjuster error") - failingAdj := adjuster.Func(func(trace ptrace.Traces) (ptrace.Traces, error) { - return trace, adjErr - }) +func (mockAdjusterError) Adjust(ptrace.Traces) error { + return assert.AnError +} +func TestSequences(t *testing.T) { tests := []struct { name string adjuster adjuster.Adjuster @@ -39,14 +40,14 @@ func TestSequences(t *testing.T) { }{ { name: "normal sequence", - adjuster: adjuster.Sequence(adj, failingAdj, adj, failingAdj), - err: fmt.Sprintf("%s\n%s", adjErr, adjErr), + adjuster: adjuster.Sequence(mockAdjuster{}, mockAdjusterError{}, mockAdjuster{}, mockAdjusterError{}), + err: fmt.Sprintf("%s\n%s", assert.AnError, assert.AnError), lastSpanID: [8]byte{0, 0, 0, 0, 0, 0, 0, 2}, }, { name: "fail fast sequence", - adjuster: adjuster.FailFastSequence(adj, failingAdj, adj, failingAdj), - err: adjErr.Error(), + adjuster: adjuster.FailFastSequence(mockAdjuster{}, mockAdjusterError{}, mockAdjuster{}, mockAdjusterError{}), + err: assert.AnError.Error(), lastSpanID: [8]byte{0, 0, 0, 0, 0, 0, 0, 1}, }, } @@ -57,12 +58,12 @@ func TestSequences(t *testing.T) { span := trace.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() span.SetSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 0}) - adjTrace, err := test.adjuster.Adjust(trace) - adjTraceSpan := adjTrace.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0) + err := test.adjuster.Adjust(trace) + require.EqualError(t, err, test.err) + adjTraceSpan := trace.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0) assert.Equal(t, span, adjTraceSpan) assert.EqualValues(t, test.lastSpanID, span.SpanID()) - require.EqualError(t, err, test.err) }) } } diff --git a/cmd/query/app/querysvc/adjuster/ipattribute.go b/cmd/query/app/querysvc/adjuster/ipattribute.go index 0ddb9b45447..4dcd70bd888 100644 --- a/cmd/query/app/querysvc/adjuster/ipattribute.go +++ b/cmd/query/app/querysvc/adjuster/ipattribute.go @@ -20,30 +20,31 @@ var ipAttributesToCorrect = map[string]struct{}{ // IPAttribute returns an adjuster that replaces numeric "ip" attributes, // which usually contain IPv4 packed into uint32, with their string // representation (e.g. "8.8.8.8""). -func IPAttribute() Adjuster { - return Func(func(traces ptrace.Traces) (ptrace.Traces, error) { - adjuster := ipAttributeAdjuster{} - resourceSpans := traces.ResourceSpans() - for i := 0; i < resourceSpans.Len(); i++ { - rs := resourceSpans.At(i) - adjuster.adjust(rs.Resource().Attributes()) - scopeSpans := rs.ScopeSpans() - for j := 0; j < scopeSpans.Len(); j++ { - ss := scopeSpans.At(j) - spans := ss.Spans() - for k := 0; k < spans.Len(); k++ { - span := spans.At(k) - adjuster.adjust(span.Attributes()) - } +func IPAttribute() IPAttributeAdjuster { + return IPAttributeAdjuster{} +} + +type IPAttributeAdjuster struct{} + +func (ia IPAttributeAdjuster) Adjust(traces ptrace.Traces) error { + resourceSpans := traces.ResourceSpans() + for i := 0; i < resourceSpans.Len(); i++ { + rs := resourceSpans.At(i) + ia.adjustAttributes(rs.Resource().Attributes()) + scopeSpans := rs.ScopeSpans() + for j := 0; j < scopeSpans.Len(); j++ { + ss := scopeSpans.At(j) + spans := ss.Spans() + for k := 0; k < spans.Len(); k++ { + span := spans.At(k) + ia.adjustAttributes(span.Attributes()) } } - return traces, nil - }) + } + return nil } -type ipAttributeAdjuster struct{} - -func (ipAttributeAdjuster) adjust(attributes pcommon.Map) { +func (IPAttributeAdjuster) adjustAttributes(attributes pcommon.Map) { adjusted := make(map[string]string) attributes.Range(func(k string, v pcommon.Value) bool { if _, ok := ipAttributesToCorrect[k]; !ok { diff --git a/cmd/query/app/querysvc/adjuster/ipattribute_test.go b/cmd/query/app/querysvc/adjuster/ipattribute_test.go index cfd9ddeea26..e55a9dd8bdc 100644 --- a/cmd/query/app/querysvc/adjuster/ipattribute_test.go +++ b/cmd/query/app/querysvc/adjuster/ipattribute_test.go @@ -58,10 +58,10 @@ func TestIPAttributeAdjuster(t *testing.T) { } } - trace, err := IPAttribute().Adjust(traces) + err := IPAttribute().Adjust(traces) require.NoError(t, err) - resourceSpan := trace.ResourceSpans().At(0) + resourceSpan := traces.ResourceSpans().At(0) assert.Equal(t, 3, resourceSpan.Resource().Attributes().Len()) assertAttribute(resourceSpan.Resource().Attributes(), "a", 42) diff --git a/cmd/query/app/querysvc/adjuster/resourceattributes.go b/cmd/query/app/querysvc/adjuster/resourceattributes.go index 0c3cd6d512f..356cd4f800f 100644 --- a/cmd/query/app/querysvc/adjuster/resourceattributes.go +++ b/cmd/query/app/querysvc/adjuster/resourceattributes.go @@ -7,6 +7,7 @@ import ( "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" + "github.com/jaegertracing/jaeger/internal/jptrace" "github.com/jaegertracing/jaeger/pkg/otelsemconv" ) @@ -28,7 +29,7 @@ func ResourceAttributes() ResourceAttributesAdjuster { type ResourceAttributesAdjuster struct{} -func (o ResourceAttributesAdjuster) Adjust(traces ptrace.Traces) (ptrace.Traces, error) { +func (o ResourceAttributesAdjuster) Adjust(traces ptrace.Traces) error { resourceSpans := traces.ResourceSpans() for i := 0; i < resourceSpans.Len(); i++ { rs := resourceSpans.At(i) @@ -43,7 +44,7 @@ func (o ResourceAttributesAdjuster) Adjust(traces ptrace.Traces) (ptrace.Traces, } } } - return traces, nil + return nil } func (ResourceAttributesAdjuster) moveAttributes(span ptrace.Span, resource pcommon.Resource) { @@ -57,7 +58,7 @@ func (ResourceAttributesAdjuster) moveAttributes(span ptrace.Span, resource pcom for k, v := range replace { existing, ok := resource.Attributes().Get(k) if ok && existing.AsRaw() != v.AsRaw() { - addWarning(span, "conflicting values between Span and Resource for attribute "+k) + jptrace.AddWarning(span, "conflicting values between Span and Resource for attribute "+k) continue } v.CopyTo(resource.Attributes().PutEmpty(k)) diff --git a/cmd/query/app/querysvc/adjuster/resourceattributes_test.go b/cmd/query/app/querysvc/adjuster/resourceattributes_test.go index 0d445671ad0..5dc5c438133 100644 --- a/cmd/query/app/querysvc/adjuster/resourceattributes_test.go +++ b/cmd/query/app/querysvc/adjuster/resourceattributes_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/ptrace" + "github.com/jaegertracing/jaeger/internal/jptrace" "github.com/jaegertracing/jaeger/pkg/otelsemconv" ) @@ -25,10 +26,9 @@ func TestResourceAttributesAdjuster_SpanWithLibraryAttributes(t *testing.T) { span.Attributes().PutStr("another_key", "another_value") adjuster := ResourceAttributes() - result, err := adjuster.Adjust(traces) - require.NoError(t, err) + require.NoError(t, adjuster.Adjust(traces)) - resultSpanAttributes := result.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Attributes() + resultSpanAttributes := traces.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Attributes() require.Equal(t, 2, resultSpanAttributes.Len()) val, ok := resultSpanAttributes.Get("random_key") require.True(t, ok) @@ -38,7 +38,7 @@ func TestResourceAttributesAdjuster_SpanWithLibraryAttributes(t *testing.T) { require.True(t, ok) require.Equal(t, "another_value", val.Str()) - resultResourceAttributes := result.ResourceSpans().At(0).Resource().Attributes() + resultResourceAttributes := traces.ResourceSpans().At(0).Resource().Attributes() val, ok = resultResourceAttributes.Get(string(otelsemconv.TelemetrySDKLanguageKey)) require.True(t, ok) @@ -68,10 +68,9 @@ func TestResourceAttributesAdjuster_SpanWithoutLibraryAttributes(t *testing.T) { span.Attributes().PutStr("random_key", "random_value") adjuster := ResourceAttributes() - result, err := adjuster.Adjust(traces) - require.NoError(t, err) + require.NoError(t, adjuster.Adjust(traces)) - resultSpanAttributes := result.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Attributes() + resultSpanAttributes := traces.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Attributes() require.Equal(t, 1, resultSpanAttributes.Len()) val, ok := resultSpanAttributes.Get("random_key") require.True(t, ok) @@ -87,10 +86,10 @@ func TestResourceAttributesAdjuster_SpanWithConflictingLibraryAttributes(t *test span.Attributes().PutStr(string(otelsemconv.TelemetrySDKLanguageKey), "Java") adjuster := ResourceAttributes() - result, err := adjuster.Adjust(traces) - require.NoError(t, err) + require.NoError(t, adjuster.Adjust(traces)) - resultSpanAttributes := result.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Attributes() + resultSpan := traces.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0) + resultSpanAttributes := resultSpan.Attributes() require.Equal(t, 3, resultSpanAttributes.Len()) val, ok := resultSpanAttributes.Get("random_key") require.True(t, ok) @@ -101,13 +100,12 @@ func TestResourceAttributesAdjuster_SpanWithConflictingLibraryAttributes(t *test require.True(t, ok) require.Equal(t, "Java", val.Str()) - val, ok = resultSpanAttributes.Get("jaeger.adjuster.warning") + warnings := jptrace.GetWarnings(resultSpan) require.True(t, ok) - warnings := val.Slice() - require.Equal(t, 1, warnings.Len()) - require.Equal(t, "conflicting values between Span and Resource for attribute telemetry.sdk.language", warnings.At(0).Str()) + require.Len(t, warnings, 1) + require.Equal(t, "conflicting values between Span and Resource for attribute telemetry.sdk.language", warnings[0]) - resultResourceAttributes := result.ResourceSpans().At(0).Resource().Attributes() + resultResourceAttributes := traces.ResourceSpans().At(0).Resource().Attributes() val, ok = resultResourceAttributes.Get(string(otelsemconv.TelemetrySDKLanguageKey)) require.True(t, ok) require.Equal(t, "Go", val.Str()) @@ -122,16 +120,15 @@ func TestResourceAttributesAdjuster_SpanWithNonConflictingLibraryAttributes(t *t span.Attributes().PutStr(string(otelsemconv.TelemetrySDKLanguageKey), "Go") adjuster := ResourceAttributes() - result, err := adjuster.Adjust(traces) - require.NoError(t, err) + require.NoError(t, adjuster.Adjust(traces)) - resultSpanAttributes := result.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Attributes() + resultSpanAttributes := traces.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Attributes() require.Equal(t, 1, resultSpanAttributes.Len()) val, ok := resultSpanAttributes.Get("random_key") require.True(t, ok) require.Equal(t, "random_value", val.Str()) - resultResourceAttributes := result.ResourceSpans().At(0).Resource().Attributes() + resultResourceAttributes := traces.ResourceSpans().At(0).Resource().Attributes() val, ok = resultResourceAttributes.Get(string(otelsemconv.TelemetrySDKLanguageKey)) require.True(t, ok) require.Equal(t, "Go", val.Str()) diff --git a/cmd/query/app/querysvc/adjuster/spanlinks.go b/cmd/query/app/querysvc/adjuster/spanlinks.go index bb93dc1f9c3..d58ad63ab39 100644 --- a/cmd/query/app/querysvc/adjuster/spanlinks.go +++ b/cmd/query/app/querysvc/adjuster/spanlinks.go @@ -8,35 +8,36 @@ import ( ) // SpanLinks creates an adjuster that removes span links with empty trace IDs. -func SpanLinks() Adjuster { - return Func(func(traces ptrace.Traces) (ptrace.Traces, error) { - adjuster := linksAdjuster{} - resourceSpans := traces.ResourceSpans() - for i := 0; i < resourceSpans.Len(); i++ { - rs := resourceSpans.At(i) - scopeSpans := rs.ScopeSpans() - for j := 0; j < scopeSpans.Len(); j++ { - ss := scopeSpans.At(j) - spans := ss.Spans() - for k := 0; k < spans.Len(); k++ { - span := spans.At(k) - adjuster.adjust(span) - } +func SpanLinks() LinksAdjuster { + return LinksAdjuster{} +} + +type LinksAdjuster struct{} + +func (la LinksAdjuster) Adjust(traces ptrace.Traces) error { + resourceSpans := traces.ResourceSpans() + for i := 0; i < resourceSpans.Len(); i++ { + rs := resourceSpans.At(i) + scopeSpans := rs.ScopeSpans() + for j := 0; j < scopeSpans.Len(); j++ { + ss := scopeSpans.At(j) + spans := ss.Spans() + for k := 0; k < spans.Len(); k++ { + span := spans.At(k) + la.adjust(span) } } - return traces, nil - }) + } + return nil } -type linksAdjuster struct{} - // adjust removes invalid links from a span. -func (l linksAdjuster) adjust(span ptrace.Span) { +func (la LinksAdjuster) adjust(span ptrace.Span) { links := span.Links() validLinks := ptrace.NewSpanLinkSlice() for i := 0; i < links.Len(); i++ { link := links.At(i) - if l.valid(link) { + if la.valid(link) { newLink := validLinks.AppendEmpty() link.CopyTo(newLink) } @@ -45,6 +46,6 @@ func (l linksAdjuster) adjust(span ptrace.Span) { } // valid checks if a span link's TraceID is not empty. -func (linksAdjuster) valid(link ptrace.SpanLink) bool { +func (LinksAdjuster) valid(link ptrace.SpanLink) bool { return !link.TraceID().IsEmpty() } diff --git a/cmd/query/app/querysvc/adjuster/spanlinks_test.go b/cmd/query/app/querysvc/adjuster/spanlinks_test.go index 9d64b5c8531..af687e50bc4 100644 --- a/cmd/query/app/querysvc/adjuster/spanlinks_test.go +++ b/cmd/query/app/querysvc/adjuster/spanlinks_test.go @@ -13,8 +13,8 @@ import ( ) func TestLinksAdjuster(t *testing.T) { - trace := ptrace.NewTraces() - resourceSpans := trace.ResourceSpans().AppendEmpty() + traces := ptrace.NewTraces() + resourceSpans := traces.ResourceSpans().AppendEmpty() scopeSpans := resourceSpans.ScopeSpans().AppendEmpty() // span with no links @@ -30,8 +30,8 @@ func TestLinksAdjuster(t *testing.T) { spanB.Links().AppendEmpty().SetTraceID(pcommon.TraceID([]byte{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0})) spanB.Links().AppendEmpty().SetTraceID(pcommon.TraceID([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})) - trace, err := SpanLinks().Adjust(trace) - spans := trace.ResourceSpans().At(0).ScopeSpans().At(0).Spans() + err := SpanLinks().Adjust(traces) + spans := traces.ResourceSpans().At(0).ScopeSpans().At(0).Spans() require.NoError(t, err) assert.Equal(t, 0, spans.At(0).Links().Len()) assert.Equal(t, 0, spans.At(1).Links().Len()) diff --git a/cmd/query/app/querysvc/adjuster/warning.go b/cmd/query/app/querysvc/adjuster/warning.go deleted file mode 100644 index e7f1331bfab..00000000000 --- a/cmd/query/app/querysvc/adjuster/warning.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2024 The Jaeger Authors. -// SPDX-License-Identifier: Apache-2.0 - -package adjuster - -import ( - "go.opentelemetry.io/collector/pdata/pcommon" - "go.opentelemetry.io/collector/pdata/ptrace" -) - -const ( - adjusterWarningAttribute = "jaeger.adjuster.warning" -) - -func addWarning(span ptrace.Span, warning string) { - var warnings pcommon.Slice - if currWarnings, ok := span.Attributes().Get(adjusterWarningAttribute); ok { - warnings = currWarnings.Slice() - } else { - warnings = span.Attributes().PutEmptySlice(adjusterWarningAttribute) - } - warnings.AppendEmpty().SetStr(warning) -} diff --git a/internal/jptrace/package_test.go b/internal/jptrace/package_test.go new file mode 100644 index 00000000000..c86c58d3df0 --- /dev/null +++ b/internal/jptrace/package_test.go @@ -0,0 +1,14 @@ +// Copyright (c) 2024 The Jaeger Authors. +// SPDX-License-Identifier: Apache-2.0 + +package jptrace + +import ( + "testing" + + "github.com/jaegertracing/jaeger/pkg/testutils" +) + +func TestMain(m *testing.M) { + testutils.VerifyGoLeaks(m) +} diff --git a/internal/jptrace/warning.go b/internal/jptrace/warning.go new file mode 100644 index 00000000000..0d96296c214 --- /dev/null +++ b/internal/jptrace/warning.go @@ -0,0 +1,39 @@ +// Copyright (c) 2024 The Jaeger Authors. +// SPDX-License-Identifier: Apache-2.0 + +package jptrace + +import ( + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/ptrace" +) + +const ( + // WarningsAttribute is the name of the span attribute where we can + // store various warnings produced from transformations, + // such as inbound sanitizers and outbound adjusters. + // The value type of the attribute is a string slice. + warningsAttribute = "jaeger.internal.warnings" +) + +func AddWarning(span ptrace.Span, warning string) { + var warnings pcommon.Slice + if currWarnings, ok := span.Attributes().Get(warningsAttribute); ok { + warnings = currWarnings.Slice() + } else { + warnings = span.Attributes().PutEmptySlice(warningsAttribute) + } + warnings.AppendEmpty().SetStr(warning) +} + +func GetWarnings(span ptrace.Span) []string { + if w, ok := span.Attributes().Get(warningsAttribute); ok { + warnings := []string{} + ws := w.Slice() + for i := 0; i < ws.Len(); i++ { + warnings = append(warnings, ws.At(i).Str()) + } + return warnings + } + return nil +} diff --git a/cmd/query/app/querysvc/adjuster/warning_test.go b/internal/jptrace/warning_test.go similarity index 54% rename from cmd/query/app/querysvc/adjuster/warning_test.go rename to internal/jptrace/warning_test.go index 209d794e639..b8e3c38032c 100644 --- a/cmd/query/app/querysvc/adjuster/warning_test.go +++ b/internal/jptrace/warning_test.go @@ -1,7 +1,7 @@ // Copyright (c) 2024 The Jaeger Authors. // SPDX-License-Identifier: Apache-2.0 -package adjuster +package jptrace import ( "testing" @@ -41,13 +41,13 @@ func TestAddWarning(t *testing.T) { span := ptrace.NewSpan() attrs := span.Attributes() if test.existing != nil { - warnings := attrs.PutEmptySlice("jaeger.adjuster.warning") + warnings := attrs.PutEmptySlice("jaeger.internal.warnings") for _, warn := range test.existing { warnings.AppendEmpty().SetStr(warn) } } - addWarning(span, test.newWarn) - warnings, ok := attrs.Get("jaeger.adjuster.warning") + AddWarning(span, test.newWarn) + warnings, ok := attrs.Get("jaeger.internal.warnings") assert.True(t, ok) assert.Equal(t, len(test.expected), warnings.Slice().Len()) for i, expectedWarn := range test.expected { @@ -56,3 +56,41 @@ func TestAddWarning(t *testing.T) { }) } } + +func TestGetWarnings(t *testing.T) { + tests := []struct { + name string + existing []string + expected []string + }{ + { + name: "get from nil warnings", + existing: nil, + expected: nil, + }, + { + name: "get from empty warnings", + existing: []string{}, + expected: []string{}, + }, + { + name: "get from existing warnings", + existing: []string{"existing warning 1", "existing warning 2"}, + expected: []string{"existing warning 1", "existing warning 2"}, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + span := ptrace.NewSpan() + attrs := span.Attributes() + if test.existing != nil { + warnings := attrs.PutEmptySlice("jaeger.internal.warnings") + for _, warn := range test.existing { + warnings.AppendEmpty().SetStr(warn) + } + } + actual := GetWarnings(span) + assert.Equal(t, test.expected, actual) + }) + } +}