diff --git a/skywalking-commons/skywalking-trace/src/main/java/com/a/eye/skywalking/trace/Span.java b/skywalking-commons/skywalking-trace/src/main/java/com/a/eye/skywalking/trace/Span.java index 9b55c1700cd160dfcae3faee0de275754f26fd89..f219b577bba9754e36740ae14c69ac5ebbd7d0d4 100644 --- a/skywalking-commons/skywalking-trace/src/main/java/com/a/eye/skywalking/trace/Span.java +++ b/skywalking-commons/skywalking-trace/src/main/java/com/a/eye/skywalking/trace/Span.java @@ -71,7 +71,7 @@ public class Span { * Value -1 means no parent span if this {@link TraceSegment}. * @param operationName {@link #operationName} */ - public Span(int spanId, int parentSpanId, String operationName){ + private Span(int spanId, int parentSpanId, String operationName){ this.spanId = spanId; this.parentSpanId = parentSpanId; this.startTime = System.currentTimeMillis(); @@ -91,6 +91,17 @@ public class Span { this(spanId, -1, operationName); } + /** + * Create a new span, by given span id and given parent {@link Span}. + * + * @param spanId given by the creator, and must be unique id in the {@link TraceSegment} + * @param parentSpan {@link Span} + * @param operationName {@link #operationName} + */ + public Span(int spanId, Span parentSpan, String operationName){ + this(spanId, parentSpan.spanId, operationName); + } + /** * Finish the active Span. * When it is finished, it will be archived by the given {@link TraceSegment}, which owners it. @@ -177,4 +188,8 @@ public class Span { log(Collections.singletonMap("event", event)); return this; } + + public int getSpanId() { + return spanId; + } } diff --git a/skywalking-commons/skywalking-trace/src/main/java/com/a/eye/skywalking/trace/TraceSegment.java b/skywalking-commons/skywalking-trace/src/main/java/com/a/eye/skywalking/trace/TraceSegment.java index 7d164f2a904b83e93a8a45b2eebfb61c6432fd55..a2db4a12f84f2ec3f8b0e7fcf33e287a81f836c4 100644 --- a/skywalking-commons/skywalking-trace/src/main/java/com/a/eye/skywalking/trace/TraceSegment.java +++ b/skywalking-commons/skywalking-trace/src/main/java/com/a/eye/skywalking/trace/TraceSegment.java @@ -96,4 +96,8 @@ public class TraceSegment { public void finish(){ this.endTime = System.currentTimeMillis(); } + + public String getTraceSegmentId() { + return traceSegmentId; + } } diff --git a/skywalking-commons/skywalking-trace/src/main/java/com/a/eye/skywalking/trace/TraceSegmentRef.java b/skywalking-commons/skywalking-trace/src/main/java/com/a/eye/skywalking/trace/TraceSegmentRef.java index 69119ced75a23a67207ab2b1b063c21f69badeff..bfe0d50e9e67f78bd614d0a7c3566a5dc3da85db 100644 --- a/skywalking-commons/skywalking-trace/src/main/java/com/a/eye/skywalking/trace/TraceSegmentRef.java +++ b/skywalking-commons/skywalking-trace/src/main/java/com/a/eye/skywalking/trace/TraceSegmentRef.java @@ -1,9 +1,40 @@ package com.a.eye.skywalking.trace; /** - * + * {@link TraceSegmentRef} is like a pointer, which ref to another {@link TraceSegment}. * * Created by wusheng on 2017/2/17. */ public class TraceSegmentRef { + /** + * {@link TraceSegment#traceSegmentId} + */ + private String traceSegmentId; + + /** + * {@link Span#spanId} + */ + private int spanId; + + /** + * Create a {@link TraceSegmentRef} instance, without any data. + */ + public TraceSegmentRef() { + } + + public String getTraceSegmentId() { + return traceSegmentId; + } + + public void setTraceSegmentId(String traceSegmentId) { + this.traceSegmentId = traceSegmentId; + } + + public int getSpanId() { + return spanId; + } + + public void setSpanId(int spanId) { + this.spanId = spanId; + } } diff --git a/skywalking-commons/skywalking-util/src/main/java/com/a/eye/skywalking/util/StringUtil.java b/skywalking-commons/skywalking-util/src/main/java/com/a/eye/skywalking/util/StringUtil.java index d7417b27d6d390a0e5aa6600fa050a1bd66635cc..aee0e9096dde2b299d79a0732ce3d85926e5fab8 100644 --- a/skywalking-commons/skywalking-util/src/main/java/com/a/eye/skywalking/util/StringUtil.java +++ b/skywalking-commons/skywalking-util/src/main/java/com/a/eye/skywalking/util/StringUtil.java @@ -7,4 +7,25 @@ public final class StringUtil { } return false; } + + public static String join(final char delimiter, final String... strings) { + if (strings.length == 0) { + return null; + } + if (strings.length == 1) { + return strings[0]; + } + int length = strings.length - 1; + for (final String s : strings) { + length += s.length(); + } + final StringBuilder sb = new StringBuilder(length); + sb.append(strings[0]); + for (int i = 1; i < strings.length; ++i) { + if (!isEmpty(strings[i])) { + sb.append(delimiter).append(strings[i]); + } + } + return sb.toString(); + } } diff --git a/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/conf/Constants.java b/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/conf/Constants.java index ba50822c69b6b03414685ebc495333e03648e72b..fa1ebc8ea388257d3c15e8efa68ddd813baf963d 100644 --- a/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/conf/Constants.java +++ b/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/conf/Constants.java @@ -7,7 +7,5 @@ public class Constants { * This is the version, which will be the first segment of traceid. * Ref {@link TraceIdGenerator#generate()} */ - public static int SDK_VERSION = 212017; - - public static final String CONTEXT_DATA_SEGMENT_SPILT_CHAR = "#&"; + public static String SDK_VERSION = "302017"; } diff --git a/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/trace/ContextCarrier.java b/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/trace/ContextCarrier.java new file mode 100644 index 0000000000000000000000000000000000000000..d9a45f819daadc4a6d575d0fadc431113865da0d --- /dev/null +++ b/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/trace/ContextCarrier.java @@ -0,0 +1,44 @@ +package com.a.eye.skywalking.trace; + +import com.a.eye.skywalking.util.StringUtil; +import java.io.Serializable; + +/** + * {@link ContextCarrier} is a data carrier of {@link TracerContext}. + * It holds the snapshot (current state) of {@link TracerContext}. + * + * Created by wusheng on 2017/2/17. + */ +public class ContextCarrier extends TraceSegmentRef implements Serializable { + + /** + * Serialize this {@link ContextCarrier} to a {@link String}, + * with '|' split. + * + * @return the serialization string. + */ + public String serialize() { + return StringUtil.join('|', this.getTraceSegmentId(), this.getSpanId() + ""); + } + + /** + * Initialize fields with the given text. + * + * @param text carries {@link #traceSegmentId} and {@link #spanId}, with '|' split. + */ + public ContextCarrier deserialize(String text) { + if(text != null){ + String[] parts = text.split("|"); + if(parts.length == 2){ + try{ + setSpanId(Integer.parseInt(parts[1])); + setTraceSegmentId(parts[0]); + }catch(NumberFormatException e){ + + } + } + } + return this; + } + +} diff --git a/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/trace/ContextManager.java b/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/trace/ContextManager.java new file mode 100644 index 0000000000000000000000000000000000000000..46f07d391fdeea928e16fb6d89b51f10953ca777 --- /dev/null +++ b/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/trace/ContextManager.java @@ -0,0 +1,26 @@ +package com.a.eye.skywalking.trace; + +/** + * {@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. + * + * What is 'ChildOf'? {@see https://github.com/opentracing/specification/blob/master/specification.md#references-between-spans} + * + * + * Created by wusheng on 2017/2/17. + */ +public enum ContextManager { + INSTANCE; + + private static ThreadLocal CONTEXT = new ThreadLocal<>(); + + public TracerContext get() { + TracerContext segment = CONTEXT.get(); + if (segment == null) { + segment = new TracerContext(); + CONTEXT.set(segment); + } + return segment; + } +} diff --git a/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/trace/TracerContext.java b/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/trace/TracerContext.java new file mode 100644 index 0000000000000000000000000000000000000000..1569cd1c01e7d6a0727bc5908b5515d776530b58 --- /dev/null +++ b/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/trace/TracerContext.java @@ -0,0 +1,135 @@ +package com.a.eye.skywalking.trace; + +import com.a.eye.skywalking.util.TraceIdGenerator; +import java.util.ArrayList; +import java.util.List; + +/** + * {@link TracerContext} maintains the context. + * You manipulate (create/finish/get) spans and (inject/extract) context. + * + * Created by wusheng on 2017/2/17. + */ +public final class TracerContext { + private TraceSegment segment; + + /** + * Active spans stored in a Stack, usually called 'ActiveSpanStack'. + * This {@link ArrayList} is the in-memory storage-structure. + * + * I use {@link ArrayList#size()} as a pointer, to the top element of 'ActiveSpanStack'. + * And provide the top 3 important methods of stack: + * {@link #pop()}, {@link #push(Span)}, {@link #peek()} + */ + private List activeSpanStack = new ArrayList(20); + + private int spanIdGenerator; + + TracerContext() { + this.segment = new TraceSegment(TraceIdGenerator.generate()); + this.spanIdGenerator = 0; + } + + /** + * Create a new span, as an active span, by the given operationName + * + * @param operationName {@link Span#operationName} + * @return the new active span. + */ + public Span createSpan(String operationName) { + Span parentSpan = peek(); + Span span; + if (parentSpan == null) { + span = new Span(spanIdGenerator++, operationName); + } else { + span = new Span(spanIdGenerator++, parentSpan, operationName); + } + push(span); + return span; + } + + /** + * @return the active span of current context. + */ + public Span activeSpan() { + Span span = peek(); + if (span == null) { + throw new IllegalStateException("No active span."); + } + return span; + } + + /** + * Stop the span. And finish the {@link #segment} if all {@link #activeSpanStack} elements are finished. + * + * @param span to finish. It must the the top element of {@link #activeSpanStack}. + */ + public void stopSpan(Span span) { + Span lastSpan = peek(); + if (lastSpan == span) { + segment.archive(pop()); + } else { + throw new IllegalStateException("Stopping the unexpected span = " + span); + } + + if (activeSpanStack.isEmpty()) { + segment.finish(); + } + } + + /** + * Give a snapshot of this {@link TracerContext}, + * and save current state to the given {@link ContextCarrier}. + * + * @param carrier holds the snapshot + */ + private void inject(ContextCarrier carrier) { + carrier.setTraceSegmentId(this.segment.getTraceSegmentId()); + carrier.setSpanId(this.activeSpan().getSpanId()); + } + + /** + * Ref this {@link ContextCarrier} to this {@link TraceSegment} + * + * @param carrier holds the snapshot, if get this {@link ContextCarrier} from remote, make sure {@link + * ContextCarrier#deserialize(String)} called. + */ + private void extract(ContextCarrier carrier) { + this.segment.ref(carrier); + } + + /** + * @return the top element of 'ActiveSpanStack', and remove it. + */ + private Span pop() { + return activeSpanStack.remove(getTopElementIdx()); + } + + /** + * Add a new Span at the top of 'ActiveSpanStack' + * + * @param span + */ + private void push(Span span) { + activeSpanStack.add(activeSpanStack.size(), span); + } + + /** + * @return the top element of 'ActiveSpanStack' only. + */ + private Span peek() { + if (activeSpanStack.isEmpty()) { + return null; + } + return activeSpanStack.get(getTopElementIdx()); + } + + /** + * Get the index of 'ActiveSpanStack' + * + * @return the index + */ + private int getTopElementIdx() { + return activeSpanStack.size() - 1; + } +} diff --git a/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/util/TraceIdGenerator.java b/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/util/TraceIdGenerator.java index 2c2673680067be6de969079fd97f6c13645584e8..78850263e455735e213b69bf6b50832285bdf8b5 100644 --- a/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/util/TraceIdGenerator.java +++ b/skywalking-sniffer/skywalking-api/src/main/java/com/a/eye/skywalking/util/TraceIdGenerator.java @@ -1,12 +1,10 @@ package com.a.eye.skywalking.util; -import java.util.UUID; - import com.a.eye.skywalking.conf.Constants; -import com.a.eye.skywalking.network.grpc.TraceId; +import java.util.UUID; public final class TraceIdGenerator { - private static final ThreadLocal ThreadTraceIdSequence = new ThreadLocal(){ + private static final ThreadLocal ThreadTraceIdSequence = new ThreadLocal() { @Override protected Integer initialValue() { return 0; @@ -32,14 +30,13 @@ public final class TraceIdGenerator { * * @return */ - public static TraceId generate() { + public static String generate() { Integer seq = ThreadTraceIdSequence.get(); seq++; ThreadTraceIdSequence.set(seq); - return TraceId.newBuilder().addSegments(Constants.SDK_VERSION) - .addSegments(System.currentTimeMillis()).addSegments(PROCESS_UUID) - .addSegments(BuriedPointMachineUtil.getProcessNo()) - .addSegments(Thread.currentThread().getId()).addSegments(seq).build(); + return StringUtil.join('.', + Constants.SDK_VERSION + "", System.currentTimeMillis() + "", PROCESS_UUID + "", + BuriedPointMachineUtil.getProcessNo() + "", Thread.currentThread().getId() + "", seq + ""); } }