Skip to content

Commit

Permalink
OpenTracing Shim: Full multiple parent support. (#4916)
Browse files Browse the repository at this point in the history
* 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 <34418638+jack-berg@users.noreply.github.com>

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

Co-authored-by: jack-berg <34418638+jack-berg@users.noreply.github.com>

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

Co-authored-by: jack-berg <34418638+jack-berg@users.noreply.github.com>

* Apply feedback.

* More feedback.

Co-authored-by: jack-berg <34418638+jack-berg@users.noreply.github.com>
  • Loading branch information
carlosalberto and jack-berg committed Nov 9, 2022
1 parent ef076c2 commit f83def7
Show file tree
Hide file tree
Showing 3 changed files with 278 additions and 31 deletions.
2 changes: 2 additions & 0 deletions opentracing-shim/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ dependencies {
api("io.opentracing:opentracing-api")
implementation(project(":semconv"))

annotationProcessor("com.google.auto.value:auto-value")

testImplementation(project(":sdk:testing"))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,35 @@
import static io.opentelemetry.api.common.AttributeKey.longKey;
import static io.opentelemetry.api.common.AttributeKey.stringKey;

import com.google.auto.value.AutoValue;
import io.opentelemetry.api.baggage.Baggage;
import io.opentelemetry.api.baggage.BaggageBuilder;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.context.Context;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import io.opentracing.References;
import io.opentracing.Span;
import io.opentracing.SpanContext;
import io.opentracing.Tracer.SpanBuilder;
import io.opentracing.tag.Tag;
import io.opentracing.tag.Tags;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;

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

// The parent will be either a Span or a SpanContext.
// Inherited baggage is supported only for the main parent.
@Nullable private SpanShim parentSpan;
@Nullable private SpanContextShim parentSpanContext;
// *All* parents are saved in this list.
private List<SpanParentInfo> allParents = Collections.emptyList();
private boolean ignoreActiveSpan;

private final List<io.opentelemetry.api.trace.SpanContext> parentLinks = new ArrayList<>();

@SuppressWarnings("rawtypes")
private final List<AttributeKey> spanBuilderAttributeKeys = new ArrayList<>();

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

private static final Attributes CHILD_OF_ATTR =
Attributes.of(
SemanticAttributes.OPENTRACING_REF_TYPE,
SemanticAttributes.OpentracingRefTypeValues.CHILD_OF);
private static final Attributes FOLLOWS_FROM_ATTR =
Attributes.of(
SemanticAttributes.OPENTRACING_REF_TYPE,
SemanticAttributes.OpentracingRefTypeValues.FOLLOWS_FROM);

public SpanBuilderShim(TelemetryInfo telemetryInfo, String spanName) {
super(telemetryInfo);
this.spanName = spanName;
Expand All @@ -57,19 +69,12 @@ public SpanBuilder asChildOf(Span parent) {

// TODO - Verify we handle a no-op Span
SpanShim spanShim = ShimUtil.getSpanShim(parent);

if (parentSpan == null && parentSpanContext == null) {
parentSpan = spanShim;
} else {
parentLinks.add(spanShim.getSpan().getSpanContext());
}

return this;
return addReference(References.CHILD_OF, spanShim.context());
}

@Override
public SpanBuilder asChildOf(SpanContext parent) {
return addReference(null, parent);
return addReference(References.CHILD_OF, parent);
}

@Override
Expand All @@ -78,13 +83,30 @@ public SpanBuilder addReference(@Nullable String referenceType, SpanContext refe
return this;
}

// TODO - Use referenceType
ReferenceType refType;
if (References.CHILD_OF.equals(referenceType)) {
refType = ReferenceType.CHILD_OF;
} else if (References.FOLLOWS_FROM.equals(referenceType)) {
refType = ReferenceType.FOLLOWS_FROM;
} else {
// Discard references with unrecognized type.
return this;
}

SpanContextShim contextShim = ShimUtil.getContextShim(referencedContext);

if (parentSpan == null && parentSpanContext == null) {
parentSpanContext = contextShim;
// Optimization for 99% situations, when there is only one parent.
if (allParents.size() == 0) {
allParents =
Collections.singletonList(
SpanParentInfo.create(
contextShim.getSpanContext(), contextShim.getBaggage(), refType));
} else {
parentLinks.add(contextShim.getSpanContext());
if (allParents.size() == 1) {
allParents = new ArrayList<>(allParents);
}
allParents.add(
SpanParentInfo.create(contextShim.getSpanContext(), contextShim.getBaggage(), refType));
}

return this;
Expand Down Expand Up @@ -186,26 +208,26 @@ public SpanBuilder withStartTimestamp(long microseconds) {
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public Span start() {
Baggage baggage = Baggage.empty();
Baggage baggage;
io.opentelemetry.api.trace.SpanBuilder builder = tracer().spanBuilder(spanName);
io.opentelemetry.api.trace.SpanContext mainParent = getMainParent(allParents);

if (ignoreActiveSpan && parentSpan == null && parentSpanContext == null) {
if (ignoreActiveSpan && mainParent == null) {
builder.setNoParent();
} else if (parentSpan != null) {
builder.setParent(Context.root().with(parentSpan.getSpan()));
baggage = ((SpanContextShim) parentSpan.context()).getBaggage();
} else if (parentSpanContext != null) {
builder.setParent(
Context.root()
.with(io.opentelemetry.api.trace.Span.wrap(parentSpanContext.getSpanContext())));
baggage = parentSpanContext.getBaggage();
baggage = Baggage.empty();
} else if (mainParent != null) {
builder.setParent(Context.root().with(io.opentelemetry.api.trace.Span.wrap(mainParent)));
baggage = getAllBaggage(allParents);
} else {
// No explicit parent Span, but extracted baggage may be available.
baggage = Baggage.current();
}

for (io.opentelemetry.api.trace.SpanContext link : parentLinks) {
builder.addLink(link);
// *All* parents are processed as Links, in order to keep the reference type value.
for (SpanParentInfo parentInfo : allParents) {
builder.addLink(
parentInfo.getSpanContext(),
parentInfo.getRefType() == ReferenceType.CHILD_OF ? CHILD_OF_ATTR : FOLLOWS_FROM_ATTR);
}

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

return new SpanShim(telemetryInfo(), span, baggage);
}

// The first SpanContext with Child Of type in the entire list is used as parent,
// else the first SpanContext is used as parent.
@Nullable
static io.opentelemetry.api.trace.SpanContext getMainParent(List<SpanParentInfo> parents) {
if (parents.size() == 0) {
return null;
}

SpanParentInfo mainParent = parents.get(0);
for (SpanParentInfo parentInfo : parents) {
if (parentInfo.getRefType() == ReferenceType.CHILD_OF) {
mainParent = parentInfo;
break;
}
}

return mainParent.getSpanContext();
}

static Baggage getAllBaggage(List<SpanParentInfo> parents) {
if (parents.size() == 0) {
return Baggage.empty();
}

if (parents.size() == 1) {
return parents.get(0).getBaggage();
}

BaggageBuilder builder = Baggage.builder();
for (SpanParentInfo parent : parents) {
parent.getBaggage().forEach((key, entry) -> builder.put(key, entry.getValue()));
}

return builder.build();
}

@AutoValue
@Immutable
abstract static class SpanParentInfo {
private static SpanParentInfo create(
io.opentelemetry.api.trace.SpanContext spanContext,
Baggage baggage,
ReferenceType refType) {
return new AutoValue_SpanBuilderShim_SpanParentInfo(spanContext, baggage, refType);
}

abstract io.opentelemetry.api.trace.SpanContext getSpanContext();

abstract Baggage getBaggage();

abstract ReferenceType getRefType();
}

enum ReferenceType {
CHILD_OF,
FOLLOWS_FROM
}
}

0 comments on commit f83def7

Please sign in to comment.