package org.skywalking.apm.agent.core.context;
import org.skywalking.apm.agent.core.boot.BootService;
import org.skywalking.apm.trace.Span;
import org.skywalking.apm.trace.TraceSegment;
/**
* {@link TracerContext} controls the whole context of {@link TraceSegment}. Any {@link TraceSegment} relates to
* single-thread, so this context use {@link ThreadLocal} to maintain the context, and make sure, since a {@link
* TraceSegment} starts, all ChildOf spans are in the same context.
* <p>
* What is 'ChildOf'? {@see https://github.com/opentracing/specification/blob/master/specification.md#references-between-spans}
* <p>
* Also, {@link ContextManager} delegates to all {@link TracerContext}'s major methods: {@link
* TracerContext#createSpan(String)}, {@link TracerContext#activeSpan()}, {@link TracerContext#stopSpan(Span)}
* <p>
* Created by wusheng on 2017/2/17.
*/
public class ContextManager implements TracerContextListener, BootService {
private static ThreadLocal<TracerContext> CONTEXT = new ThreadLocal<TracerContext>();
private static TracerContext get() {
TracerContext segment = CONTEXT.get();
if (segment == null) {
segment = new TracerContext();
CONTEXT.set(segment);
}
return segment;
}
/**
* @see {@link TracerContext#inject(ContextCarrier)}
*/
public static void inject(ContextCarrier carrier) {
get().inject(carrier);
}
/**
* @see {@link TracerContext#extract(ContextCarrier)}
*/
public static void extract(ContextCarrier carrier) {
get().extract(carrier);
}
/**
* @return the first global trace id if exist. Otherwise, "N/A".
*/
public static String getGlobalTraceId() {
TracerContext segment = CONTEXT.get();
if (segment == null) {
return "N/A";
} else {
return segment.getGlobalTraceId();
}
}
public static Span createSpan(String operationName) {
return get().createSpan(operationName, false);
}
public static Span createSpan(String operationName, long startTime) {
return get().createSpan(operationName, startTime, false);
}
public static Span createLeafSpan(String operationName) {
return get().createSpan(operationName, true);
}
public static Span createLeafSpan(String operationName, long startTime) {
return get().createSpan(operationName, startTime, true);
}
public static Span activeSpan() {
return get().activeSpan();
}
public static void stopSpan(Span span) {
get().stopSpan(span);
}
public static void stopSpan(Long endTime) {
get().stopSpan(activeSpan(), endTime);
}
public static void stopSpan() {
stopSpan(activeSpan());
}
@Override
public void bootUp() {
TracerContext.ListenerManager.add(this);
}
@Override
public void afterFinished(TraceSegment traceSegment) {
CONTEXT.remove();
}
}