diff --git a/src/main/java/com/profiler/context/Annotation.java b/src/main/java/com/profiler/context/Annotation.java new file mode 100644 index 000000000..64507bea4 --- /dev/null +++ b/src/main/java/com/profiler/context/Annotation.java @@ -0,0 +1,52 @@ +package com.profiler.context; + +public class Annotation { + + protected final long timestamp; + protected final String value; + protected final EndPoint endPoint; + + protected long processStart; + protected long processEnd; + + /** + * @param timestamp + * when was this annotation created? microseconds from epoch + * @param value + * description of what happened at the timestamp could for + * example be "cache miss for key: x" + * @param endPoint + * host this annotation was created on + */ + public Annotation(long timestamp, String value, EndPoint endPoint) { + this.timestamp = timestamp; + this.value = value; + this.endPoint = endPoint; + } + + public long getTimestamp() { + return timestamp; + } + + public void processStart() { + processStart = System.nanoTime(); + } + + public void processEnd() { + processEnd = System.nanoTime(); + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("Annotation["); + sb.append("Timestamp=").append(timestamp); + sb.append("Value=").append(value); + sb.append("EndPoint=").append(endPoint); + sb.append("ProcessStart=").append(processStart); + sb.append("ProcessEnd=").append(processEnd); + sb.append("]"); + + return sb.toString(); + } +} diff --git a/src/main/java/com/profiler/context/BinaryAnnotation.java b/src/main/java/com/profiler/context/BinaryAnnotation.java new file mode 100644 index 000000000..20ee53397 --- /dev/null +++ b/src/main/java/com/profiler/context/BinaryAnnotation.java @@ -0,0 +1,19 @@ +package com.profiler.context; + +public class BinaryAnnotation extends Annotation { + + protected final byte[] binaryValue; + + /** + * @param timestamp + * when was this annotation created? microseconds from epoch + * @param value + * detailed description of what happened at the timestamp + * @param host + * host this annotation was created on + */ + public BinaryAnnotation(long timestamp, byte[] value, EndPoint host) { + super(timestamp, null, host); + this.binaryValue = value; + } +} diff --git a/src/main/java/com/profiler/context/EndPoint.java b/src/main/java/com/profiler/context/EndPoint.java new file mode 100644 index 000000000..818614f1c --- /dev/null +++ b/src/main/java/com/profiler/context/EndPoint.java @@ -0,0 +1,22 @@ +package com.profiler.context; + +public class EndPoint { + + public static final EndPoint NONE = null; + + private final String protocol; + private final String ip; + private final int port; + private final String name; + + public EndPoint(String protocol, String ip, int port, String name) { + this.protocol = protocol; + this.ip = ip; + this.port = port; + this.name = name; + } + + public String toString() { + return "EndPoint[Protocol=" + protocol + ", IP=" + ip + ", Port=" + port + ", Name=" + name + "]"; + } +} diff --git a/src/main/java/com/profiler/context/IDFactory.java b/src/main/java/com/profiler/context/IDFactory.java new file mode 100644 index 000000000..f7e35f26f --- /dev/null +++ b/src/main/java/com/profiler/context/IDFactory.java @@ -0,0 +1,11 @@ +package com.profiler.context; + +import java.util.UUID; + +public class IDFactory { + + public static String newTraceID() { + UUID uuid = UUID.randomUUID(); + return uuid.toString(); + } +} diff --git a/src/main/java/com/profiler/context/RequestContext.java b/src/main/java/com/profiler/context/RequestContext.java new file mode 100644 index 000000000..128c22821 --- /dev/null +++ b/src/main/java/com/profiler/context/RequestContext.java @@ -0,0 +1,24 @@ +package com.profiler.context; + +import com.profiler.util.NamedThreadLocal; + +public class RequestContext { + + private static final ThreadLocal span = new NamedThreadLocal("Span"); + + public static Span getSpan(String traceID, int parentSpanID, String name, boolean debug) { + Span ctx = span.get(); + if (ctx == null) { + ctx = new Span(traceID, parentSpanID, name, debug); + span.set(ctx); + } + return ctx; + } + + /** + * Calling from Span.flush() + */ + public static void removeCurrentContext() { + span.remove(); + } +} diff --git a/src/main/java/com/profiler/context/Span.java b/src/main/java/com/profiler/context/Span.java new file mode 100644 index 000000000..67c6248a3 --- /dev/null +++ b/src/main/java/com/profiler/context/Span.java @@ -0,0 +1,79 @@ +package com.profiler.context; + +import java.util.Comparator; +import java.util.SortedSet; +import java.util.TreeSet; + +/** + * A span represents one RPC request. A trace is made up of many spans. + * + * @author netspider + * + */ +public class Span { + + private final String traceID; + private final int spanID; + private final int parentSpanID; + private final String name; + private final long createTime; + private final boolean debug; + + private final SortedSet annotations = new TreeSet(new Comparator() { + @Override + public int compare(Annotation a1, Annotation a2) { + return (int) (a1.getTimestamp() - a2.getTimestamp()); + } + }); + + public Span(String traceID, int parentSpanID, String name, boolean debug) { + if (traceID == null) { + this.traceID = traceID; + } else { + this.traceID = IDFactory.newTraceID(); + } + + if (parentSpanID < 0) { + this.spanID = 1; + } else { + this.spanID = ++parentSpanID; + } + + this.parentSpanID = parentSpanID; + this.name = name; + this.createTime = System.nanoTime(); + this.debug = debug; + } + + public boolean addAnnotation(Annotation annotation) { + return annotations.add(annotation); + } + + private void flush() { + System.out.println("TODO: flush collected data."); + RequestContext.removeCurrentContext(); + } + + public String getTraceID() { + return traceID; + } + + public int getNextSpanID() { + return spanID + 1; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("Span["); + sb.append("TraceID=").append(traceID); + sb.append(", SpanID=").append(spanID); + sb.append(", ParentSpanID=").append(parentSpanID); + sb.append(", CreateTime=").append(createTime); + sb.append(", Name=").append(name); + sb.append(", Annotations=").append(annotations); + sb.append("]"); + + return sb.toString(); + } +}