Skip to content

Commit f83def7

Browse files
OpenTracing Shim: Full multiple parent support. (#4916)
* Full multiple parent support. This includes: * The Baggage union of ALL parents is used. * All parents are added as Links, in order to preserve the OpenTracing reference type as an attribute (either CHILD_OF or FOLLOWS_FROM). * Update opentracing-shim/src/main/java/io/opentelemetry/opentracingshim/SpanBuilderShim.java Co-authored-by: jack-berg <[email protected]> * Update opentracing-shim/src/main/java/io/opentelemetry/opentracingshim/SpanBuilderShim.java Co-authored-by: jack-berg <[email protected]> * Update opentracing-shim/src/main/java/io/opentelemetry/opentracingshim/SpanBuilderShim.java Co-authored-by: jack-berg <[email protected]> * Apply feedback. * More feedback. Co-authored-by: jack-berg <[email protected]>
1 parent ef076c2 commit f83def7

File tree

3 files changed

+278
-31
lines changed

3 files changed

+278
-31
lines changed

opentracing-shim/build.gradle.kts

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ dependencies {
1212
api("io.opentracing:opentracing-api")
1313
implementation(project(":semconv"))
1414

15+
annotationProcessor("com.google.auto.value:auto-value")
16+
1517
testImplementation(project(":sdk:testing"))
1618
}
1719

opentracing-shim/src/main/java/io/opentelemetry/opentracingshim/SpanBuilderShim.java

+111-31
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,35 @@
1010
import static io.opentelemetry.api.common.AttributeKey.longKey;
1111
import static io.opentelemetry.api.common.AttributeKey.stringKey;
1212

13+
import com.google.auto.value.AutoValue;
1314
import io.opentelemetry.api.baggage.Baggage;
15+
import io.opentelemetry.api.baggage.BaggageBuilder;
1416
import io.opentelemetry.api.common.AttributeKey;
17+
import io.opentelemetry.api.common.Attributes;
1518
import io.opentelemetry.api.trace.SpanKind;
1619
import io.opentelemetry.api.trace.StatusCode;
1720
import io.opentelemetry.context.Context;
21+
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
22+
import io.opentracing.References;
1823
import io.opentracing.Span;
1924
import io.opentracing.SpanContext;
2025
import io.opentracing.Tracer.SpanBuilder;
2126
import io.opentracing.tag.Tag;
2227
import io.opentracing.tag.Tags;
2328
import java.util.ArrayList;
29+
import java.util.Collections;
2430
import java.util.List;
2531
import java.util.concurrent.TimeUnit;
2632
import javax.annotation.Nullable;
33+
import javax.annotation.concurrent.Immutable;
2734

2835
final class SpanBuilderShim extends BaseShimObject implements SpanBuilder {
2936
private final String spanName;
3037

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();
3540
private boolean ignoreActiveSpan;
3641

37-
private final List<io.opentelemetry.api.trace.SpanContext> parentLinks = new ArrayList<>();
38-
3942
@SuppressWarnings("rawtypes")
4043
private final List<AttributeKey> spanBuilderAttributeKeys = new ArrayList<>();
4144

@@ -44,6 +47,15 @@ final class SpanBuilderShim extends BaseShimObject implements SpanBuilder {
4447
private boolean error;
4548
private long startTimestampMicros;
4649

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+
4759
public SpanBuilderShim(TelemetryInfo telemetryInfo, String spanName) {
4860
super(telemetryInfo);
4961
this.spanName = spanName;
@@ -57,19 +69,12 @@ public SpanBuilder asChildOf(Span parent) {
5769

5870
// TODO - Verify we handle a no-op Span
5971
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());
6873
}
6974

7075
@Override
7176
public SpanBuilder asChildOf(SpanContext parent) {
72-
return addReference(null, parent);
77+
return addReference(References.CHILD_OF, parent);
7378
}
7479

7580
@Override
@@ -78,13 +83,30 @@ public SpanBuilder addReference(@Nullable String referenceType, SpanContext refe
7883
return this;
7984
}
8085

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+
8296
SpanContextShim contextShim = ShimUtil.getContextShim(referencedContext);
8397

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));
86104
} 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));
88110
}
89111

90112
return this;
@@ -186,26 +208,26 @@ public SpanBuilder withStartTimestamp(long microseconds) {
186208
@SuppressWarnings({"rawtypes", "unchecked"})
187209
@Override
188210
public Span start() {
189-
Baggage baggage = Baggage.empty();
211+
Baggage baggage;
190212
io.opentelemetry.api.trace.SpanBuilder builder = tracer().spanBuilder(spanName);
213+
io.opentelemetry.api.trace.SpanContext mainParent = getMainParent(allParents);
191214

192-
if (ignoreActiveSpan && parentSpan == null && parentSpanContext == null) {
215+
if (ignoreActiveSpan && mainParent == null) {
193216
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);
202221
} else {
203222
// No explicit parent Span, but extracted baggage may be available.
204223
baggage = Baggage.current();
205224
}
206225

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);
209231
}
210232

211233
if (spanKind != null) {
@@ -232,4 +254,62 @@ public Span start() {
232254

233255
return new SpanShim(telemetryInfo(), span, baggage);
234256
}
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+
}
235315
}

0 commit comments

Comments
 (0)