@@ -5,15 +5,19 @@ package exporterhelper // import "go.opentelemetry.io/collector/exporter/exporte
55
66import (
77 "context"
8+ "encoding/json"
89 "errors"
910
1011 "go.uber.org/zap"
1112
13+ "go.opentelemetry.io/otel/trace"
14+
1215 "go.opentelemetry.io/collector/component"
1316 "go.opentelemetry.io/collector/consumer"
1417 "go.opentelemetry.io/collector/consumer/consumererror"
1518 "go.opentelemetry.io/collector/exporter"
1619 "go.opentelemetry.io/collector/exporter/exporterhelper/internal"
20+ "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch"
1721 "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request"
1822 "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer"
1923 "go.opentelemetry.io/collector/pdata/ptrace"
@@ -43,36 +47,145 @@ func NewTracesQueueBatchSettings() QueueBatchSettings {
4347 }
4448}
4549
50+ // TraceStateSerializable represents a serializable version of TraceState
51+ type TraceStateSerializable struct {
52+ Members []struct {
53+ Key string `json:"key"`
54+ Value string `json:"value"`
55+ } `json:"members"`
56+ }
57+
58+ // traceStateToSerializable converts a TraceState to a serializable format
59+ func traceStateToSerializable (ts trace.TraceState ) TraceStateSerializable {
60+ result := TraceStateSerializable {
61+ Members : make ([]struct {
62+ Key string `json:"key"`
63+ Value string `json:"value"`
64+ }, 0 , ts .Len ()),
65+ }
66+
67+ ts .Walk (func (key , value string ) bool {
68+ result .Members = append (result .Members , struct {
69+ Key string `json:"key"`
70+ Value string `json:"value"`
71+ }{
72+ Key : key ,
73+ Value : value ,
74+ })
75+ return true
76+ })
77+
78+ return result
79+ }
80+
81+ // serializableToTraceState converts a serializable format back to TraceState
82+ func serializableToTraceState (ts TraceStateSerializable ) (trace.TraceState , error ) {
83+ var result trace.TraceState
84+ var err error
85+
86+ for _ , m := range ts .Members {
87+ result , err = result .Insert (m .Key , m .Value )
88+ if err != nil {
89+ return trace.TraceState {}, err
90+ }
91+ }
92+
93+ return result , nil
94+ }
95+
96+ // Update SerializableLink to use the new TraceState serialization
97+ type SerializableLink struct {
98+ TraceID [16 ]byte `json:"trace_id"`
99+ SpanID [8 ]byte `json:"span_id"`
100+ TraceFlags byte `json:"trace_flags"`
101+ TraceState TraceStateSerializable `json:"trace_state"`
102+ }
103+
104+ func linkToSerializable (l trace.Link ) SerializableLink {
105+ return SerializableLink {
106+ TraceID : l .SpanContext .TraceID (),
107+ SpanID : l .SpanContext .SpanID (),
108+ TraceFlags : byte (l .SpanContext .TraceFlags ()),
109+ TraceState : traceStateToSerializable (l .SpanContext .TraceState ()),
110+ }
111+ }
112+
113+ func serializableToLink (sl SerializableLink ) trace.Link {
114+ ts , err := serializableToTraceState (sl .TraceState )
115+ if err != nil {
116+ // If there's an error parsing the trace state, use an empty one
117+ ts = trace.TraceState {}
118+ }
119+
120+ sc := trace .NewSpanContext (trace.SpanContextConfig {
121+ TraceID : sl .TraceID ,
122+ SpanID : sl .SpanID ,
123+ TraceFlags : trace .TraceFlags (sl .TraceFlags ),
124+ TraceState : ts ,
125+ })
126+ return trace.Link {
127+ SpanContext : sc ,
128+ }
129+ }
130+
46131type tracesRequest struct {
47132 td ptrace.Traces
133+ links []trace.Link
48134 cachedSize int
49135}
50136
51- func newTracesRequest (td ptrace.Traces ) Request {
137+ func newTracesRequest (td ptrace.Traces , links []trace. Link ) Request {
52138 return & tracesRequest {
53139 td : td ,
140+ links : links ,
54141 cachedSize : - 1 ,
55142 }
56143}
57144
58145type tracesEncoding struct {}
59146
147+ type tracesWithLinks struct {
148+ Traces []byte `json:"traces"`
149+ Links []SerializableLink `json:"links"`
150+ }
151+
60152func (tracesEncoding ) Unmarshal (bytes []byte ) (Request , error ) {
61- traces , err := tracesUnmarshaler .UnmarshalTraces (bytes )
153+ var twl tracesWithLinks
154+ if err := json .Unmarshal (bytes , & twl ); err != nil {
155+ return nil , err
156+ }
157+ traces , err := tracesUnmarshaler .UnmarshalTraces (twl .Traces )
62158 if err != nil {
63159 return nil , err
64160 }
65- return newTracesRequest (traces ), nil
161+ links := make ([]trace.Link , len (twl .Links ))
162+ for i , sl := range twl .Links {
163+ links [i ] = serializableToLink (sl )
164+ }
165+ return newTracesRequest (traces , links ), nil
66166}
67167
68168func (tracesEncoding ) Marshal (req Request ) ([]byte , error ) {
69- return tracesMarshaler .MarshalTraces (req .(* tracesRequest ).td )
169+ tr := req .(* tracesRequest )
170+ tracesBytes , err := tracesMarshaler .MarshalTraces (tr .td )
171+ if err != nil {
172+ return nil , err
173+ }
174+ serializableLinks := make ([]SerializableLink , len (tr .links ))
175+ for i , l := range tr .links {
176+ serializableLinks [i ] = linkToSerializable (l )
177+ }
178+ twl := tracesWithLinks {
179+ Traces : tracesBytes ,
180+ Links : serializableLinks ,
181+ }
182+ return json .Marshal (twl )
70183}
71184
72185func (req * tracesRequest ) OnError (err error ) Request {
73186 var traceError consumererror.Traces
74187 if errors .As (err , & traceError ) {
75- return newTracesRequest (traceError .Data ())
188+ return newTracesRequest (traceError .Data (), req . links )
76189 }
77190 return req
78191}
@@ -81,6 +194,11 @@ func (req *tracesRequest) ItemsCount() int {
81194 return req .td .SpanCount ()
82195}
83196
197+ // Links returns the trace links associated with this request.
198+ func (req * tracesRequest ) Links () []trace.Link {
199+ return req .links
200+ }
201+
84202func (req * tracesRequest ) size (sizer sizer.TracesSizer ) int {
85203 if req .cachedSize == - 1 {
86204 req .cachedSize = sizer .TracesSize (req .td )
@@ -124,8 +242,9 @@ func requestConsumeFromTraces(pusher consumer.ConsumeTracesFunc) RequestConsumeF
124242
125243// requestFromTraces returns a RequestConverterFunc that converts ptrace.Traces into a Request.
126244func requestFromTraces () RequestConverterFunc [ptrace.Traces ] {
127- return func (_ context.Context , traces ptrace.Traces ) (Request , error ) {
128- return newTracesRequest (traces ), nil
245+ return func (ctx context.Context , traces ptrace.Traces ) (Request , error ) {
246+ links := queuebatch .LinksFromContext (ctx )
247+ return newTracesRequest (traces , links ), nil
129248 }
130249}
131250
0 commit comments