brave.RealSpan Maven / Gradle / Ivy
/*
* Copyright The OpenZipkin Authors
* SPDX-License-Identifier: Apache-2.0
*/
package brave;
import brave.handler.MutableSpan;
import brave.internal.recorder.PendingSpans;
import brave.propagation.TraceContext;
/** This wraps the public api and guards access to a mutable span. */
final class RealSpan extends Span {
final TraceContext context;
final PendingSpans pendingSpans;
final MutableSpan state;
final Clock clock;
RealSpan(TraceContext context,
PendingSpans pendingSpans,
MutableSpan state,
Clock clock
) {
this.context = context;
this.pendingSpans = pendingSpans;
this.state = state;
this.clock = clock;
}
@Override public boolean isNoop() {
return false;
}
@Override public TraceContext context() {
return context;
}
@Override public SpanCustomizer customizer() {
return new SpanCustomizerShield(this);
}
@Override public Span start() {
return start(clock.currentTimeMicroseconds());
}
@Override public Span start(long timestamp) {
synchronized (state) {
state.startTimestamp(timestamp);
}
return this;
}
@Override public Span name(String name) {
synchronized (state) {
state.name(name);
}
return this;
}
@Override public Span kind(Kind kind) {
synchronized (state) {
state.kind(kind);
}
return this;
}
@Override public Span annotate(String value) {
return annotate(clock.currentTimeMicroseconds(), value);
}
@Override public Span annotate(long timestamp, String value) {
// Modern instrumentation should not send annotations such as this, but we leniently
// accept them rather than fail. This for example allows old bridges like to Brave v3 to work
if ("cs".equals(value)) {
synchronized (state) {
state.kind(Span.Kind.CLIENT);
state.startTimestamp(timestamp);
}
} else if ("sr".equals(value)) {
synchronized (state) {
state.kind(Span.Kind.SERVER);
state.startTimestamp(timestamp);
}
} else if ("cr".equals(value)) {
synchronized (state) {
state.kind(Span.Kind.CLIENT);
}
finish(timestamp);
} else if ("ss".equals(value)) {
synchronized (state) {
state.kind(Span.Kind.SERVER);
}
finish(timestamp);
} else {
synchronized (state) {
state.annotate(timestamp, value);
}
}
return this;
}
@Override public Span tag(String key, String value) {
synchronized (state) {
state.tag(key, value);
}
return this;
}
@Override public Span error(Throwable throwable) {
synchronized (state) {
state.error(throwable);
}
return this;
}
@Override public Span remoteServiceName(String remoteServiceName) {
synchronized (state) {
state.remoteServiceName(remoteServiceName);
}
return this;
}
@Override public boolean remoteIpAndPort(String remoteIp, int remotePort) {
synchronized (state) {
return state.remoteIpAndPort(remoteIp, remotePort);
}
}
@Override public void finish() {
finish(0L);
}
@Override public void finish(long timestamp) {
synchronized (state) {
pendingSpans.finish(context, timestamp);
}
}
@Override public void abandon() {
pendingSpans.abandon(context);
}
@Override public void flush() {
pendingSpans.flush(context);
}
@Override public String toString() {
return "RealSpan(" + context + ")";
}
/**
* This also matches equals against a lazy span. The rationale is least surprise to the user, as
* code should not act differently given an instance of lazy or {@link RealSpan}.
*/
@Override public boolean equals(Object o) {
if (o == this) return true;
return isEqualToRealOrLazySpan(context, o);
}
// We don't compare a RealSpan vs a NoopSpan as they can never equal each other.
// RealSpan's are always locally sampled and Noop ones are always not.
static boolean isEqualToRealOrLazySpan(TraceContext context, Object o) {
if (o instanceof LazySpan) {
return context.equals(((LazySpan) o).context);
} else if (o instanceof RealSpan) {
return context.equals(((RealSpan) o).context);
}
return false;
}
@Override public int hashCode() {
return context.hashCode();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy