10
10
import static io .opentelemetry .api .common .AttributeKey .longKey ;
11
11
import static io .opentelemetry .api .common .AttributeKey .stringKey ;
12
12
13
+ import com .google .auto .value .AutoValue ;
13
14
import io .opentelemetry .api .baggage .Baggage ;
15
+ import io .opentelemetry .api .baggage .BaggageBuilder ;
14
16
import io .opentelemetry .api .common .AttributeKey ;
17
+ import io .opentelemetry .api .common .Attributes ;
15
18
import io .opentelemetry .api .trace .SpanKind ;
16
19
import io .opentelemetry .api .trace .StatusCode ;
17
20
import io .opentelemetry .context .Context ;
21
+ import io .opentelemetry .semconv .trace .attributes .SemanticAttributes ;
22
+ import io .opentracing .References ;
18
23
import io .opentracing .Span ;
19
24
import io .opentracing .SpanContext ;
20
25
import io .opentracing .Tracer .SpanBuilder ;
21
26
import io .opentracing .tag .Tag ;
22
27
import io .opentracing .tag .Tags ;
23
28
import java .util .ArrayList ;
29
+ import java .util .Collections ;
24
30
import java .util .List ;
25
31
import java .util .concurrent .TimeUnit ;
26
32
import javax .annotation .Nullable ;
33
+ import javax .annotation .concurrent .Immutable ;
27
34
28
35
final class SpanBuilderShim extends BaseShimObject implements SpanBuilder {
29
36
private final String spanName ;
30
37
31
- // The parent will be either a Span or a SpanContext.
32
- // Inherited baggage is supported only for the main parent.
33
- @ Nullable private SpanShim parentSpan ;
34
- @ Nullable private SpanContextShim parentSpanContext ;
38
+ // *All* parents are saved in this list.
39
+ private List <SpanParentInfo > allParents = Collections .emptyList ();
35
40
private boolean ignoreActiveSpan ;
36
41
37
- private final List <io .opentelemetry .api .trace .SpanContext > parentLinks = new ArrayList <>();
38
-
39
42
@ SuppressWarnings ("rawtypes" )
40
43
private final List <AttributeKey > spanBuilderAttributeKeys = new ArrayList <>();
41
44
@@ -44,6 +47,15 @@ final class SpanBuilderShim extends BaseShimObject implements SpanBuilder {
44
47
private boolean error ;
45
48
private long startTimestampMicros ;
46
49
50
+ private static final Attributes CHILD_OF_ATTR =
51
+ Attributes .of (
52
+ SemanticAttributes .OPENTRACING_REF_TYPE ,
53
+ SemanticAttributes .OpentracingRefTypeValues .CHILD_OF );
54
+ private static final Attributes FOLLOWS_FROM_ATTR =
55
+ Attributes .of (
56
+ SemanticAttributes .OPENTRACING_REF_TYPE ,
57
+ SemanticAttributes .OpentracingRefTypeValues .FOLLOWS_FROM );
58
+
47
59
public SpanBuilderShim (TelemetryInfo telemetryInfo , String spanName ) {
48
60
super (telemetryInfo );
49
61
this .spanName = spanName ;
@@ -57,19 +69,12 @@ public SpanBuilder asChildOf(Span parent) {
57
69
58
70
// TODO - Verify we handle a no-op Span
59
71
SpanShim spanShim = ShimUtil .getSpanShim (parent );
60
-
61
- if (parentSpan == null && parentSpanContext == null ) {
62
- parentSpan = spanShim ;
63
- } else {
64
- parentLinks .add (spanShim .getSpan ().getSpanContext ());
65
- }
66
-
67
- return this ;
72
+ return addReference (References .CHILD_OF , spanShim .context ());
68
73
}
69
74
70
75
@ Override
71
76
public SpanBuilder asChildOf (SpanContext parent ) {
72
- return addReference (null , parent );
77
+ return addReference (References . CHILD_OF , parent );
73
78
}
74
79
75
80
@ Override
@@ -78,13 +83,30 @@ public SpanBuilder addReference(@Nullable String referenceType, SpanContext refe
78
83
return this ;
79
84
}
80
85
81
- // TODO - Use referenceType
86
+ ReferenceType refType ;
87
+ if (References .CHILD_OF .equals (referenceType )) {
88
+ refType = ReferenceType .CHILD_OF ;
89
+ } else if (References .FOLLOWS_FROM .equals (referenceType )) {
90
+ refType = ReferenceType .FOLLOWS_FROM ;
91
+ } else {
92
+ // Discard references with unrecognized type.
93
+ return this ;
94
+ }
95
+
82
96
SpanContextShim contextShim = ShimUtil .getContextShim (referencedContext );
83
97
84
- if (parentSpan == null && parentSpanContext == null ) {
85
- parentSpanContext = contextShim ;
98
+ // Optimization for 99% situations, when there is only one parent.
99
+ if (allParents .size () == 0 ) {
100
+ allParents =
101
+ Collections .singletonList (
102
+ SpanParentInfo .create (
103
+ contextShim .getSpanContext (), contextShim .getBaggage (), refType ));
86
104
} else {
87
- parentLinks .add (contextShim .getSpanContext ());
105
+ if (allParents .size () == 1 ) {
106
+ allParents = new ArrayList <>(allParents );
107
+ }
108
+ allParents .add (
109
+ SpanParentInfo .create (contextShim .getSpanContext (), contextShim .getBaggage (), refType ));
88
110
}
89
111
90
112
return this ;
@@ -186,26 +208,26 @@ public SpanBuilder withStartTimestamp(long microseconds) {
186
208
@ SuppressWarnings ({"rawtypes" , "unchecked" })
187
209
@ Override
188
210
public Span start () {
189
- Baggage baggage = Baggage . empty () ;
211
+ Baggage baggage ;
190
212
io .opentelemetry .api .trace .SpanBuilder builder = tracer ().spanBuilder (spanName );
213
+ io .opentelemetry .api .trace .SpanContext mainParent = getMainParent (allParents );
191
214
192
- if (ignoreActiveSpan && parentSpan == null && parentSpanContext == null ) {
215
+ if (ignoreActiveSpan && mainParent == null ) {
193
216
builder .setNoParent ();
194
- } else if (parentSpan != null ) {
195
- builder .setParent (Context .root ().with (parentSpan .getSpan ()));
196
- baggage = ((SpanContextShim ) parentSpan .context ()).getBaggage ();
197
- } else if (parentSpanContext != null ) {
198
- builder .setParent (
199
- Context .root ()
200
- .with (io .opentelemetry .api .trace .Span .wrap (parentSpanContext .getSpanContext ())));
201
- baggage = parentSpanContext .getBaggage ();
217
+ baggage = Baggage .empty ();
218
+ } else if (mainParent != null ) {
219
+ builder .setParent (Context .root ().with (io .opentelemetry .api .trace .Span .wrap (mainParent )));
220
+ baggage = getAllBaggage (allParents );
202
221
} else {
203
222
// No explicit parent Span, but extracted baggage may be available.
204
223
baggage = Baggage .current ();
205
224
}
206
225
207
- for (io .opentelemetry .api .trace .SpanContext link : parentLinks ) {
208
- builder .addLink (link );
226
+ // *All* parents are processed as Links, in order to keep the reference type value.
227
+ for (SpanParentInfo parentInfo : allParents ) {
228
+ builder .addLink (
229
+ parentInfo .getSpanContext (),
230
+ parentInfo .getRefType () == ReferenceType .CHILD_OF ? CHILD_OF_ATTR : FOLLOWS_FROM_ATTR );
209
231
}
210
232
211
233
if (spanKind != null ) {
@@ -232,4 +254,62 @@ public Span start() {
232
254
233
255
return new SpanShim (telemetryInfo (), span , baggage );
234
256
}
257
+
258
+ // The first SpanContext with Child Of type in the entire list is used as parent,
259
+ // else the first SpanContext is used as parent.
260
+ @ Nullable
261
+ static io .opentelemetry .api .trace .SpanContext getMainParent (List <SpanParentInfo > parents ) {
262
+ if (parents .size () == 0 ) {
263
+ return null ;
264
+ }
265
+
266
+ SpanParentInfo mainParent = parents .get (0 );
267
+ for (SpanParentInfo parentInfo : parents ) {
268
+ if (parentInfo .getRefType () == ReferenceType .CHILD_OF ) {
269
+ mainParent = parentInfo ;
270
+ break ;
271
+ }
272
+ }
273
+
274
+ return mainParent .getSpanContext ();
275
+ }
276
+
277
+ static Baggage getAllBaggage (List <SpanParentInfo > parents ) {
278
+ if (parents .size () == 0 ) {
279
+ return Baggage .empty ();
280
+ }
281
+
282
+ if (parents .size () == 1 ) {
283
+ return parents .get (0 ).getBaggage ();
284
+ }
285
+
286
+ BaggageBuilder builder = Baggage .builder ();
287
+ for (SpanParentInfo parent : parents ) {
288
+ parent .getBaggage ().forEach ((key , entry ) -> builder .put (key , entry .getValue ()));
289
+ }
290
+
291
+ return builder .build ();
292
+ }
293
+
294
+ @ AutoValue
295
+ @ Immutable
296
+ abstract static class SpanParentInfo {
297
+ private static SpanParentInfo create (
298
+ io .opentelemetry .api .trace .SpanContext spanContext ,
299
+ Baggage baggage ,
300
+ ReferenceType refType ) {
301
+ return new AutoValue_SpanBuilderShim_SpanParentInfo (spanContext , baggage , refType );
302
+ }
303
+
304
+ abstract io .opentelemetry .api .trace .SpanContext getSpanContext ();
305
+
306
+ abstract Baggage getBaggage ();
307
+
308
+ abstract ReferenceType getRefType ();
309
+ }
310
+
311
+ enum ReferenceType {
312
+ CHILD_OF ,
313
+ FOLLOWS_FROM
314
+ }
235
315
}
0 commit comments