// Copyright 2024 William Perron. All rights reserved. MIT license package transform import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/sdk/instrumentation" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/trace" ) func TestTransformSpan(t *testing.T) { sdkspanslice := make([]sdktrace.ReadOnlySpan, 1) start := time.Unix(1000, 0) end := start.Add(5 * time.Second) evtts := time.Unix(1500, 0) stringVals := []string{"first", "second"} intVals := []int{1, 2, 3} floatVals := []float64{1.1, 2.2, 3.3} boolVals := []bool{true, false} sdkspanslice[0] = tracetest.SpanStub{ Name: "span-stub", SpanContext: trace.SpanContext{}. WithSpanID(trace.SpanID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}). WithTraceID(trace.TraceID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}). WithTraceState(must(trace.ParseTraceState("foo=bar"))), Parent: trace.SpanContext{}. WithSpanID(trace.SpanID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11}). WithTraceID(trace.TraceID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}). WithTraceState(must(trace.ParseTraceState("foo=bar"))), SpanKind: trace.SpanKindServer, StartTime: start, EndTime: end, Attributes: []attribute.KeyValue{ { Key: "stringkey", Value: attribute.StringValue("stringval"), }, { Key: "intkey", Value: attribute.IntValue(123), }, { Key: "floatkey", Value: attribute.Float64Value(111.2), }, { Key: "boolkey", Value: attribute.BoolValue(true), }, { Key: "stringslicekey", Value: attribute.StringSliceValue(stringVals), }, { Key: "intslicekey", Value: attribute.IntSliceValue(intVals), }, { Key: "floatslicekey", Value: attribute.Float64SliceValue(floatVals), }, { Key: "boolslicekey", Value: attribute.BoolSliceValue(boolVals), }, }, Events: []sdktrace.Event{ { Name: "spanevent", Attributes: []attribute.KeyValue{ { Key: "eventstringkey", Value: attribute.StringValue("eventstringval"), }, }, DroppedAttributeCount: 4, Time: evtts, }, }, Links: []sdktrace.Link{ { SpanContext: trace.NewSpanContext(trace.SpanContextConfig{ TraceID: [16]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, SpanID: [8]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, TraceFlags: 1, TraceState: must(trace.ParseTraceState("foo=bar")), Remote: false, }), Attributes: []attribute.KeyValue{ { Key: "linkstringkey", Value: attribute.StringValue("linkstringval"), }, }, DroppedAttributeCount: 5, }, }, Status: sdktrace.Status{ Code: codes.Ok, Description: "OK", }, DroppedAttributes: 1, DroppedEvents: 2, DroppedLinks: 3, ChildSpanCount: 0, Resource: resource.NewWithAttributes("https://opentelemetry.io/schemas/1.24.0", attribute.KeyValue{Key: "service.name", Value: attribute.StringValue("test-service")}, ), InstrumentationLibrary: instrumentation.Scope{ Name: "test-tracer", Version: "0.0.1", SchemaURL: "https://opentelemetry.io/schemas/1.24.0", }, }.Snapshot() spans := Spans(sdkspanslice) assert.Equal(t, 1, spans.ResourceSpans().Len()) for i := 0; i < spans.ResourceSpans().Len(); i++ { require.Less(t, i, 1) rs := spans.ResourceSpans().At(i) res := rs.Resource() exp := pcommon.NewMap() exp.PutStr("service.name", "test-service") assert.Equal(t, exp, res.Attributes()) assert.Equal(t, uint32(0), res.DroppedAttributesCount()) for j := 0; j < rs.ScopeSpans().Len(); j++ { require.Less(t, j, 1) ss := rs.ScopeSpans().At(j) for k := 0; k < ss.Spans().Len(); k++ { require.Less(t, k, 1) span := ss.Spans().At(k) ts := pcommon.NewTraceState() ts.FromRaw("foo=bar") assert.Equal(t, pcommon.SpanID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, span.SpanID()) assert.Equal(t, pcommon.TraceID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, span.TraceID()) assert.Equal(t, pcommon.SpanID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11}, span.ParentSpanID()) assert.Equal(t, ts, span.TraceState()) assert.Equal(t, "span-stub", span.Name()) assert.Equal(t, ptrace.SpanKindServer, span.Kind()) assert.Equal(t, ptrace.StatusCodeOk, span.Status().Code()) assert.Equal(t, "OK", span.Status().Message()) assert.Equal(t, pcommon.NewTimestampFromTime(start), span.StartTimestamp()) assert.Equal(t, pcommon.NewTimestampFromTime(end), span.EndTimestamp()) assert.Equal(t, uint32(1), span.DroppedAttributesCount()) assert.Equal(t, uint32(2), span.DroppedEventsCount()) assert.Equal(t, uint32(3), span.DroppedLinksCount()) a, ok := span.Attributes().Get("stringkey") assert.True(t, ok) assert.Equal(t, "stringval", a.Str()) a, ok = span.Attributes().Get("intkey") assert.True(t, ok) assert.Equal(t, int64(123), a.Int()) a, ok = span.Attributes().Get("floatkey") assert.True(t, ok) assert.Equal(t, float64(111.2), a.Double()) a, ok = span.Attributes().Get("boolkey") assert.True(t, ok) assert.Equal(t, true, a.Bool()) a, ok = span.Attributes().Get("stringslicekey") assert.True(t, ok) for i := 0; i < a.Slice().Len(); i++ { v := a.Slice().At(i) assert.Equal(t, stringVals[i], v.Str()) } a, ok = span.Attributes().Get("intslicekey") assert.True(t, ok) for i := 0; i < a.Slice().Len(); i++ { v := a.Slice().At(i) assert.Equal(t, int64(intVals[i]), v.Int()) } a, ok = span.Attributes().Get("floatslicekey") assert.True(t, ok) for i := 0; i < a.Slice().Len(); i++ { v := a.Slice().At(i) assert.Equal(t, floatVals[i], v.Double()) } a, ok = span.Attributes().Get("boolslicekey") assert.True(t, ok) for i := 0; i < a.Slice().Len(); i++ { v := a.Slice().At(i) assert.Equal(t, boolVals[i], v.Bool()) } assert.Equal(t, 1, span.Events().Len()) ev := span.Events().At(0) assert.Equal(t, evtts.UTC(), ev.Timestamp().AsTime()) assert.Equal(t, "spanevent", ev.Name()) assert.Equal(t, uint32(4), ev.DroppedAttributesCount()) a, ok = ev.Attributes().Get("eventstringkey") assert.True(t, ok) assert.Equal(t, "eventstringval", a.Str()) assert.Equal(t, 1, span.Links().Len()) ln := span.Links().At(0) assert.Equal(t, pcommon.TraceID([16]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}), ln.TraceID()) assert.Equal(t, pcommon.SpanID([8]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}), ln.SpanID()) assert.Equal(t, ts, ln.TraceState()) assert.Equal(t, uint32(5), ln.DroppedAttributesCount()) a, ok = ln.Attributes().Get("linkstringkey") assert.True(t, ok) assert.Equal(t, "linkstringval", a.Str()) } } } } func must[T any](v T, err error) T { if err != nil { panic(err) } return v }