@@ -2,6 +2,7 @@ package main
2
2
3
3
import (
4
4
"context"
5
+ "encoding/binary"
5
6
"fmt"
6
7
"strconv"
7
8
"strings"
@@ -10,10 +11,80 @@ import (
10
11
"go.opentelemetry.io/otel/attribute"
11
12
"go.opentelemetry.io/otel/codes"
12
13
otel_trace "go.opentelemetry.io/otel/trace"
14
+ "gopkg.in/DataDog/dd-trace-go.v1/ddtrace"
13
15
ddotel "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/opentelemetry"
14
16
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
15
17
)
16
18
19
+ func ConvertKeyValsToAttributes (keyVals map [string ]* ListVal ) map [string ][]attribute.KeyValue {
20
+ attributes := make ([]attribute.KeyValue , 0 , len (keyVals ))
21
+ attributesStringified := make ([]attribute.KeyValue , 0 , len (keyVals ))
22
+ for k , lv := range keyVals {
23
+ n := len (lv .GetVal ())
24
+ if n == 0 {
25
+ continue
26
+ }
27
+ // all values are represented as slices
28
+ first := lv .GetVal ()[0 ]
29
+ switch first .Val .(type ) {
30
+ case * AttrVal_StringVal :
31
+ inp := make ([]string , n )
32
+ for i , v := range lv .GetVal () {
33
+ inp [i ] = v .GetStringVal ()
34
+ }
35
+ attributesStringified = append (attributesStringified , attribute .String (k , "[" + strings .Join (inp , ", " )+ "]" ))
36
+ if len (inp ) > 1 {
37
+ attributes = append (attributes , attribute .StringSlice (k , inp ))
38
+ } else {
39
+ attributes = append (attributes , attribute .String (k , inp [0 ]))
40
+ }
41
+ case * AttrVal_BoolVal :
42
+ inp := make ([]bool , n )
43
+ stringifiedInp := make ([]string , n )
44
+ for i , v := range lv .GetVal () {
45
+ inp [i ] = v .GetBoolVal ()
46
+ stringifiedInp [i ] = strconv .FormatBool (v .GetBoolVal ())
47
+ }
48
+ attributesStringified = append (attributesStringified , attribute .String (k , "[" + strings .Join (stringifiedInp , ", " )+ "]" ))
49
+ if len (inp ) > 1 {
50
+ attributes = append (attributes , attribute .BoolSlice (k , inp ))
51
+ } else {
52
+ attributes = append (attributes , attribute .Bool (k , inp [0 ]))
53
+ }
54
+ case * AttrVal_DoubleVal :
55
+ inp := make ([]float64 , n )
56
+ stringifiedInp := make ([]string , n )
57
+ for i , v := range lv .GetVal () {
58
+ inp [i ] = v .GetDoubleVal ()
59
+ stringifiedInp [i ] = strconv .FormatFloat (v .GetDoubleVal (), 'f' , - 1 , 64 )
60
+ }
61
+ attributesStringified = append (attributesStringified , attribute .String (k , "[" + strings .Join (stringifiedInp , ", " )+ "]" ))
62
+ if len (inp ) > 1 {
63
+ attributes = append (attributes , attribute .Float64Slice (k , inp ))
64
+ } else {
65
+ attributes = append (attributes , attribute .Float64 (k , inp [0 ]))
66
+ }
67
+ case * AttrVal_IntegerVal :
68
+ inp := make ([]int64 , n )
69
+ stringifiedInp := make ([]string , n )
70
+ for i , v := range lv .GetVal () {
71
+ inp [i ] = v .GetIntegerVal ()
72
+ stringifiedInp [i ] = strconv .FormatInt (v .GetIntegerVal (), 10 )
73
+ }
74
+ attributesStringified = append (attributesStringified , attribute .String (k , "[" + strings .Join (stringifiedInp , ", " )+ "]" ))
75
+ if len (inp ) > 1 {
76
+ attributes = append (attributes , attribute .Int64Slice (k , inp ))
77
+ } else {
78
+ attributes = append (attributes , attribute .Int64 (k , inp [0 ]))
79
+ }
80
+ }
81
+ }
82
+ return map [string ][]attribute.KeyValue {
83
+ "0" : attributes ,
84
+ "1" : attributesStringified ,
85
+ }
86
+ }
87
+
17
88
func (s * apmClientServer ) OtelStartSpan (ctx context.Context , args * OtelStartSpanArgs ) (* OtelStartSpanReturn , error ) {
18
89
if s .tracer == nil {
19
90
s .tracer = s .tp .Tracer ("" )
@@ -35,56 +106,7 @@ func (s *apmClientServer) OtelStartSpan(ctx context.Context, args *OtelStartSpan
35
106
otelOpts = append (otelOpts , otel_trace .WithTimestamp (tm ))
36
107
}
37
108
if args .GetAttributes () != nil {
38
- for k , lv := range args .GetAttributes ().KeyVals {
39
- n := len (lv .GetVal ())
40
- if n == 0 {
41
- continue
42
- }
43
- // all values are represented as slices
44
- first := lv .GetVal ()[0 ]
45
- switch first .Val .(type ) {
46
- case * AttrVal_StringVal :
47
- inp := make ([]string , n )
48
- for i , v := range lv .GetVal () {
49
- inp [i ] = v .GetStringVal ()
50
- }
51
- if len (inp ) > 1 {
52
- otelOpts = append (otelOpts , otel_trace .WithAttributes (attribute .StringSlice (k , inp )))
53
- } else {
54
- otelOpts = append (otelOpts , otel_trace .WithAttributes (attribute .String (k , inp [0 ])))
55
- }
56
- case * AttrVal_BoolVal :
57
- inp := make ([]bool , n )
58
- for i , v := range lv .GetVal () {
59
- inp [i ] = v .GetBoolVal ()
60
- }
61
- if len (inp ) > 1 {
62
- otelOpts = append (otelOpts , otel_trace .WithAttributes (attribute .BoolSlice (k , inp )))
63
- } else {
64
- otelOpts = append (otelOpts , otel_trace .WithAttributes (attribute .Bool (k , inp [0 ])))
65
- }
66
- case * AttrVal_DoubleVal :
67
- inp := make ([]float64 , n )
68
- for i , v := range lv .GetVal () {
69
- inp [i ] = v .GetDoubleVal ()
70
- }
71
- if len (inp ) > 1 {
72
- otelOpts = append (otelOpts , otel_trace .WithAttributes (attribute .Float64Slice (k , inp )))
73
- } else {
74
- otelOpts = append (otelOpts , otel_trace .WithAttributes (attribute .Float64 (k , inp [0 ])))
75
- }
76
- case * AttrVal_IntegerVal :
77
- inp := make ([]int64 , n )
78
- for i , v := range lv .GetVal () {
79
- inp [i ] = v .GetIntegerVal ()
80
- }
81
- if len (inp ) > 1 {
82
- otelOpts = append (otelOpts , otel_trace .WithAttributes (attribute .Int64Slice (k , inp )))
83
- } else {
84
- otelOpts = append (otelOpts , otel_trace .WithAttributes (attribute .Int64 (k , inp [0 ])))
85
- }
86
- }
87
- }
109
+ otelOpts = append (otelOpts , otel_trace .WithAttributes (ConvertKeyValsToAttributes (args .GetAttributes ().KeyVals )["0" ]... ))
88
110
}
89
111
if args .GetHttpHeaders () != nil && len (args .HttpHeaders .HttpHeaders ) != 0 {
90
112
headers := map [string ]string {}
@@ -102,18 +124,67 @@ func (s *apmClientServer) OtelStartSpan(ctx context.Context, args *OtelStartSpan
102
124
ddOpts = append (ddOpts , tracer .ChildOf (sctx ))
103
125
}
104
126
}
127
+
128
+ if links := args .GetSpanLinks (); links != nil {
129
+ for _ , link := range links {
130
+ switch from := link .From .(type ) {
131
+ case * SpanLink_ParentId :
132
+ if _ , ok := s .otelSpans [from .ParentId ]; ok {
133
+ otelOpts = append (otelOpts , otel_trace .WithLinks (otel_trace.Link {SpanContext : s .otelSpans [from .ParentId ].span .SpanContext (), Attributes : ConvertKeyValsToAttributes (link .GetAttributes ().KeyVals )["1" ]}))
134
+ }
135
+ case * SpanLink_HttpHeaders :
136
+ headers := map [string ]string {}
137
+ for _ , headerTuple := range from .HttpHeaders .HttpHeaders {
138
+ k := headerTuple .GetKey ()
139
+ v := headerTuple .GetValue ()
140
+ if k != "" && v != "" {
141
+ headers [k ] = v
142
+ }
143
+ }
144
+ extractedContext , _ := tracer .NewPropagator (nil ).Extract (tracer .TextMapCarrier (headers ))
145
+ state , _ := otel_trace .ParseTraceState (headers ["tracestate" ])
146
+
147
+ var traceID otel_trace.TraceID
148
+ var spanID otel_trace.SpanID
149
+ if w3cCtx , ok := extractedContext .(ddtrace.SpanContextW3C ); ok {
150
+ traceID = w3cCtx .TraceID128Bytes ()
151
+ } else {
152
+ fmt .Printf ("Non-W3C context found in span, unable to get full 128 bit trace id" )
153
+ uint64ToByte (extractedContext .TraceID (), traceID [:])
154
+ }
155
+ uint64ToByte (extractedContext .SpanID (), spanID [:])
156
+ config := otel_trace.SpanContextConfig {
157
+ TraceID : traceID ,
158
+ SpanID : spanID ,
159
+ TraceState : state ,
160
+ }
161
+ var newCtx = otel_trace .NewSpanContext (config )
162
+ otelOpts = append (otelOpts , otel_trace .WithLinks (otel_trace.Link {
163
+ SpanContext : newCtx ,
164
+ Attributes : ConvertKeyValsToAttributes (link .GetAttributes ().KeyVals )["1" ],
165
+ }))
166
+ }
167
+
168
+ }
169
+ }
170
+
105
171
ctx , span := s .tracer .Start (ddotel .ContextWithStartOptions (pCtx , ddOpts ... ), args .Name , otelOpts ... )
106
172
hexSpanId := hex2int (span .SpanContext ().SpanID ().String ())
107
173
s .otelSpans [hexSpanId ] = spanContext {
108
174
span : span ,
109
175
ctx : ctx ,
110
176
}
177
+
111
178
return & OtelStartSpanReturn {
112
179
SpanId : hexSpanId ,
113
180
TraceId : hex2int (span .SpanContext ().TraceID ().String ()),
114
181
}, nil
115
182
}
116
183
184
+ func uint64ToByte (n uint64 , b []byte ) {
185
+ binary .BigEndian .PutUint64 (b , n )
186
+ }
187
+
117
188
func (s * apmClientServer ) OtelEndSpan (ctx context.Context , args * OtelEndSpanArgs ) (* OtelEndSpanReturn , error ) {
118
189
sctx , ok := s .otelSpans [args .Id ]
119
190
if ! ok {
0 commit comments