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

Merge SpanContext into Span and make DefaultSpan private #1712

Closed
wants to merge 2 commits into from
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@

import io.grpc.Context;
import io.opentelemetry.context.propagation.TextMapPropagator.Setter;
import io.opentelemetry.trace.DefaultSpan;
import io.opentelemetry.trace.SpanContext;
import io.opentelemetry.trace.Span;
import io.opentelemetry.trace.TraceFlags;
import io.opentelemetry.trace.TraceState;
import io.opentelemetry.trace.TracingContextUtils;
Expand All @@ -43,13 +42,13 @@
@State(Scope.Thread)
public class HttpTraceContextInjectBenchmark {

private static final List<SpanContext> spanContexts =
private static final List<Span> spans =
Arrays.asList(
createTestSpanContext("905734c59b913b4a905734c59b913b4a", "9909983295041501"),
createTestSpanContext("21196a77f299580e21196a77f299580e", "993a97ee3691eb26"),
createTestSpanContext("2e7d0ad2390617702e7d0ad239061770", "d49582a2de984b86"),
createTestSpanContext("905734c59b913b4a905734c59b913b4a", "776ff807b787538a"),
createTestSpanContext("68ec932c33b3f2ee68ec932c33b3f2ee", "68ec932c33b3f2ee"));
createTestSpan("905734c59b913b4a905734c59b913b4a", "9909983295041501"),
createTestSpan("21196a77f299580e21196a77f299580e", "993a97ee3691eb26"),
createTestSpan("2e7d0ad2390617702e7d0ad239061770", "d49582a2de984b86"),
createTestSpan("905734c59b913b4a905734c59b913b4a", "776ff807b787538a"),
createTestSpan("68ec932c33b3f2ee68ec932c33b3f2ee", "68ec932c33b3f2ee"));
private static final int COUNT = 5; // spanContexts.size()
private final HttpTraceContext httpTraceContext = HttpTraceContext.getInstance();
private final Map<String, String> carrier = new HashMap<>();
Expand All @@ -60,7 +59,7 @@ public void set(Map<String, String> carrier, String key, String value) {
carrier.put(key, value);
}
};
private final List<Context> contexts = createContexts(spanContexts);
private final List<Context> contexts = createContexts(spans);

/** Benchmark for measuring inject with default trace state and sampled trace options. */
@Benchmark
Expand All @@ -77,16 +76,16 @@ public Map<String, String> measureInject() {
return carrier;
}

private static SpanContext createTestSpanContext(String traceId, String spanId) {
private static Span createTestSpan(String traceId, String spanId) {
byte sampledTraceOptions = TraceFlags.getSampled();
TraceState traceStateDefault = TraceState.builder().build();
return SpanContext.create(traceId, spanId, sampledTraceOptions, traceStateDefault);
return Span.getPropagated(traceId, spanId, sampledTraceOptions, traceStateDefault);
}

private static List<Context> createContexts(List<SpanContext> spanContexts) {
private static List<Context> createContexts(List<Span> spans) {
List<Context> contexts = new ArrayList<>();
for (SpanContext context : spanContexts) {
contexts.add(TracingContextUtils.withSpan(DefaultSpan.create(context), Context.ROOT));
for (Span span : spans) {
contexts.add(TracingContextUtils.withSpan(span, Context.ROOT));
}
return contexts;
}
Expand Down
103 changes: 74 additions & 29 deletions api/src/main/java/io/opentelemetry/trace/DefaultSpan.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import io.opentelemetry.common.AttributeKey;
import io.opentelemetry.common.Attributes;
import java.util.Objects;
import javax.annotation.concurrent.Immutable;

/**
Expand All @@ -29,35 +30,63 @@
* @since 0.1.0
*/
@Immutable
public final class DefaultSpan implements Span {

private static final DefaultSpan INVALID = new DefaultSpan(SpanContext.getInvalid());

/**
* Returns a {@link DefaultSpan} with an invalid {@link SpanContext}.
*
* @return a {@code DefaultSpan} with an invalid {@code SpanContext}.
* @since 0.1.0
*/
public static Span getInvalid() {
return INVALID;
final class DefaultSpan implements Span {

static final Span INVALID =
new DefaultSpan(
TraceId.getInvalid(),
SpanId.getInvalid(),
TraceFlags.getDefault(),
TraceState.getDefault(),
/* isRemote= */ false);

private final String traceIdHex;
private final String spanIdHex;
private final byte traceFlags;
private final TraceState traceState;
private final boolean isRemote;

DefaultSpan(
String traceIdHex,
String spanIdHex,
byte traceFlags,
TraceState traceState,
boolean isRemote) {
this.traceIdHex = traceIdHex != null ? traceIdHex : TraceId.getInvalid();
this.spanIdHex = spanIdHex != null ? spanIdHex : SpanId.getInvalid();
this.traceFlags = traceFlags;
this.traceState = traceState != null ? traceState : TraceState.getDefault();
this.isRemote = isRemote;
}

/**
* Creates an instance of this class with the {@link SpanContext}.
*
* @param spanContext the {@code SpanContext}.
* @return a {@link DefaultSpan}.
* @since 0.1.0
*/
public static Span create(SpanContext spanContext) {
return new DefaultSpan(spanContext);
@Override
public String getTraceIdAsHexString() {
return traceIdHex;
}

@Override
public String getSpanIdAsHexString() {
return spanIdHex;
}

private final SpanContext spanContext;
@Override
public byte getTraceFlags() {
return traceFlags;
}

@Override
public TraceState getTraceState() {
return traceState;
}

@Override
public boolean isSampled() {
return TraceFlags.isSampled(traceFlags);
}

DefaultSpan(SpanContext spanContext) {
this.spanContext = spanContext;
@Override
public boolean isRemote() {
return isRemote;
}

@Override
Expand Down Expand Up @@ -111,11 +140,6 @@ public void end() {}
@Override
public void end(EndSpanOptions endOptions) {}

@Override
public SpanContext getContext() {
return spanContext;
}

@Override
public boolean isRecording() {
return false;
Expand All @@ -125,4 +149,25 @@ public boolean isRecording() {
public String toString() {
return "DefaultSpan";
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof DefaultSpan)) {
return false;
}
DefaultSpan that = (DefaultSpan) o;
return traceFlags == that.traceFlags
&& isRemote == that.isRemote
&& traceIdHex.equals(that.traceIdHex)
&& spanIdHex.equals(that.spanIdHex)
&& traceState.equals(that.traceState);
}

@Override
public int hashCode() {
return Objects.hash(traceIdHex, spanIdHex, traceFlags, traceState, isRemote);
}
}
18 changes: 8 additions & 10 deletions api/src/main/java/io/opentelemetry/trace/DefaultTracer.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,39 +66,37 @@ static NoopSpanBuilder create(String spanName) {
return new NoopSpanBuilder(spanName);
}

@Nullable private SpanContext spanContext;
@Nullable private Span parent;

@Override
public Span startSpan() {
if (spanContext == null) {
spanContext = TracingContextUtils.getCurrentSpan().getContext();
if (parent == null) {
parent = TracingContextUtils.getCurrentSpan();
}

return spanContext != null && !SpanContext.getInvalid().equals(spanContext)
? new DefaultSpan(spanContext)
: DefaultSpan.getInvalid();
return parent.isValid() ? parent : Span.getInvalid();
}

@Override
public NoopSpanBuilder setParent(Context context) {
Utils.checkNotNull(context, "context");
spanContext = TracingContextUtils.getSpan(context).getContext();
parent = TracingContextUtils.getSpan(context);
return this;
}

@Override
public NoopSpanBuilder setNoParent() {
spanContext = SpanContext.getInvalid();
parent = Span.getInvalid();
return this;
}

@Override
public NoopSpanBuilder addLink(SpanContext spanContext) {
public NoopSpanBuilder addLink(Span span) {
return this;
}

@Override
public NoopSpanBuilder addLink(SpanContext spanContext, Attributes attributes) {
public NoopSpanBuilder addLink(Span span, Attributes attributes) {
return this;
}

Expand Down
15 changes: 8 additions & 7 deletions api/src/main/java/io/opentelemetry/trace/Link.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@
*/
@ThreadSafe
public interface Link {
/**
* Returns the {@code SpanContext}.
*
* @return the {@code SpanContext}.
* @since 0.1.0
*/
SpanContext getContext();

String getTraceIdAsHexString();

String getSpanIdAsHexString();

TraceState getTraceState();

byte getTraceFlags();
Comment on lines +33 to +39
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This actually seems worse than before. Could we return a DefaultSpan here instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link is strange in being over-coupled to export right now. I don't think export structures should be based on e.g., Span so I'll look at it in #1714.


/**
* Returns the set of attributes.
Expand Down
82 changes: 69 additions & 13 deletions api/src/main/java/io/opentelemetry/trace/Span.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import javax.annotation.concurrent.ThreadSafe;

/**
* An interface that represents a span. It has an associated {@link SpanContext}.
* An interface that represents a span.
*
* <p>Spans are created by the {@link Builder#startSpan} method.
*
Expand All @@ -34,6 +34,70 @@
@ThreadSafe
public interface Span {

/**
* Returns an invalid {@link Span}. An invalid {@link Span} is used when tracing is disabled,
* usually because there is no OpenTelemetry SDK installed.
*/
static Span getInvalid() {
return DefaultSpan.INVALID;
}

/**
* Returns a {@link Span} that has been propagated from a remote parent. This span does not
* correspond to processing in the current process and is used to set as the parent of one that
* is.
*/
static Span getPropagated(String traceId, String spanId, byte traceFlags, TraceState traceState) {
return new DefaultSpan(traceId, spanId, traceFlags, traceState, /* isRemote= */ true);
}

/**
* Returns an unsampled {@link Span}. Because the {@link Span} is unsampled, it will not be
* exported and all operations are no-op.
*/
static Span getUnsampled(String traceId, String spanId, TraceState traceState) {
return new DefaultSpan(
traceId, spanId, TraceFlags.getDefault(), traceState, /* isRemote= */ false);
}

/** Returns the trace ID of this {@link Span}. */
String getTraceIdAsHexString();

String getSpanIdAsHexString();

byte getTraceFlags();

TraceState getTraceState();

default byte[] getTraceIdBytes() {
return TraceId.bytesFromHex(getTraceIdAsHexString(), 0);
}

default byte[] getSpanIdBytes() {
return SpanId.bytesFromHex(getSpanIdAsHexString(), 0);
}

boolean isSampled();

default void copyTraceFlagsHexTo(char[] dest, int destOffset) {
dest[destOffset] = '0';
dest[destOffset + 1] = isSampled() ? '1' : '0';
}

/**
* Returns {@code true} if this {@link Span} is valid. An invalid {@link Span} is used when
* tracing isn't enabled, for example because there is no OpenTelemetry SDK registered.
*/
default boolean isValid() {
return TraceId.isValid(getTraceIdAsHexString()) && SpanId.isValid(getSpanIdAsHexString());
}

/**
* Returns {@code true} if this {@link Span} was propagated from a remote parent and does not
* correspond to any processing in this process.
*/
boolean isRemote();

/**
* Type of span. Can be used to specify additional relationships between spans in addition to a
* parent/child relationship.
Expand Down Expand Up @@ -291,14 +355,6 @@ enum Kind {
*/
void end(EndSpanOptions endOptions);

/**
* Returns the {@code SpanContext} associated with this {@code Span}.
*
* @return the {@code SpanContext} associated with this {@code Span}.
* @since 0.1.0
*/
SpanContext getContext();

/**
* Returns {@code true} if this {@code Span} records tracing events (e.g. {@link
* #addEvent(String)}, {@link #setAttribute(String, long)}).
Expand Down Expand Up @@ -430,26 +486,26 @@ interface Builder {
/**
* Adds a {@link Link} to the newly created {@code Span}.
*
* @param spanContext the context of the linked {@code Span}.
* @param span the {@link Span} to link to.
* @return this.
* @throws NullPointerException if {@code spanContext} is {@code null}.
* @see #addLink(Link)
* @since 0.1.0
*/
Builder addLink(SpanContext spanContext);
Builder addLink(Span span);

/**
* Adds a {@link Link} to the newly created {@code Span}.
*
* @param spanContext the context of the linked {@code Span}.
* @param span the {@link Span} to link to.
* @param attributes the attributes of the {@code Link}.
* @return this.
* @throws NullPointerException if {@code spanContext} is {@code null}.
* @throws NullPointerException if {@code attributes} is {@code null}.
* @see #addLink(Link)
* @since 0.1.0
*/
Builder addLink(SpanContext spanContext, Attributes attributes);
Builder addLink(Span span, Attributes attributes);

/**
* Adds a {@link Link} to the newly created {@code Span}.
Expand Down
Loading