Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenTracing Shim: Full multiple parent support. #4916

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
jack-berg marked this conversation as resolved.
Show resolved Hide resolved
CHILD_OF,
FOLLOWS_FROM
}
}
Loading