diff --git a/dd-trace/src/main/java/com/datadoghq/trace/DDActiveSpan.java b/dd-trace/src/main/java/com/datadoghq/trace/DDActiveSpan.java new file mode 100644 index 0000000000..05849490d5 --- /dev/null +++ b/dd-trace/src/main/java/com/datadoghq/trace/DDActiveSpan.java @@ -0,0 +1,59 @@ +package com.datadoghq.trace; + +import io.opentracing.ActiveSpan; + +/** + * Base implementation for opentracing {@link ActiveSpan} + */ +public class DDActiveSpan extends DDBaseSpan implements ActiveSpan{ + + protected final DDActiveSpan parent; + + protected DDActiveSpan(DDActiveSpan parent,DDSpan span) { + super(span.startTimeMicro, span.context()); + this.startTimeNano = span.startTimeNano; + this.durationNano = span.durationNano; + this.parent = parent; + } + + protected DDActiveSpan(DDActiveSpan parent,long timestampMicro, DDSpanContext context) { + super(timestampMicro, context); + this.parent = parent; + } + + /** + * @return the generating parent if not null + */ + public DDActiveSpan getParent() { + return parent; + } + + @Override + public void deactivate() { + context().getTracer().deactivate(this); + finish(); + } + + @Override + public Continuation capture() { + return new DDContinuation(); + } + + @Override + protected ActiveSpan thisInstance() { + return this; + } + + public class DDContinuation implements Continuation{ + + @Override + public ActiveSpan activate() { + //Reactivate the current span + context().getTracer().makeActive(DDActiveSpan.this); + + //And return the encapsulating ActiveSpan + return DDActiveSpan.this; + } + + } +} diff --git a/dd-trace/src/main/java/com/datadoghq/trace/DDBaseSpan.java b/dd-trace/src/main/java/com/datadoghq/trace/DDBaseSpan.java new file mode 100644 index 0000000000..83c5b87aee --- /dev/null +++ b/dd-trace/src/main/java/com/datadoghq/trace/DDBaseSpan.java @@ -0,0 +1,332 @@ +package com.datadoghq.trace; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; + +import io.opentracing.BaseSpan; + +@SuppressWarnings("rawtypes") +public abstract class DDBaseSpan implements BaseSpan { + + /** + * StartTime stores the creation time of the span in milliseconds + */ + protected long startTimeMicro; + /** + * StartTimeNano stores the only the nanoseconds for more accuracy + */ + protected long startTimeNano; + /** + * The duration in nanoseconds computed using the startTimeMicro and startTimeNano + */ + protected long durationNano; + /** + * The context attached to the span + */ + protected final DDSpanContext context; + + private final static Logger logger = LoggerFactory.getLogger(DDBaseSpan.class); + + /** + * A simple constructor. + * Currently, users have + * + * @param timestampMicro if set, use this time instead of the auto-generated time + * @param context the context + */ + protected DDBaseSpan( + long timestampMicro, + DDSpanContext context) { + + this.context = context; + + // record the start time in nano (current milli + nano delta) + if (timestampMicro == 0L) { + this.startTimeMicro = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()); + } else { + this.startTimeMicro = timestampMicro; + } + this.startTimeNano = System.nanoTime(); + + // track each span of the trace + this.context.getTrace().add(this); + + } + + public final void finish() { + this.durationNano = System.nanoTime() - startTimeNano; + afterFinish(); + } + + public final void finish(long stoptimeMicros) { + this.durationNano = TimeUnit.MICROSECONDS.toNanos(stoptimeMicros - this.startTimeMicro); + afterFinish(); + } + + /** + * Close the span. If the current span is the parent, check if each child has also been closed + * If not, warned it + */ + protected final void afterFinish() { + logger.debug("{} - Closing the span.", this); + + // warn if one of the parent's children is not finished + if (this.isRootSpan()) { + List> spans = this.context().getTrace(); + + for (DDBaseSpan span : spans) { + if (((DDBaseSpan) span).getDurationNano() == 0L) { + logger.warn("{} - The parent span is marked as finished but this span isn't. You have to close each children.", this); + } + } + this.context.getTracer().write(this.context.getTrace()); + logger.debug("{} - Write the trace", this); + } + } + + /* (non-Javadoc) + * @see io.opentracing.Span#close() + */ + public final void close() { + this.finish(); + } + + /** + * Check if the span is the root parent. It means that the traceId is the same as the spanId + * + * @return true if root, false otherwise + */ + protected final boolean isRootSpan() { + + if (context().getTrace().isEmpty()) { + return false; + } + // First item of the array AND tracer set + DDSpan first = (DDSpan) context().getTrace().get(0); + return first.context().getSpanId() == this.context().getSpanId() && this.context.getTracer() != null; + } + + + /* (non-Javadoc) + * @see io.opentracing.BaseSpan#setTag(java.lang.String, java.lang.String) + */ + @Override + public final S setTag(String tag, String value) { + this.context().setTag(tag, (Object) value); + return thisInstance(); + } + + + /* (non-Javadoc) + * @see io.opentracing.BaseSpan#setTag(java.lang.String, boolean) + */ + @Override + public final S setTag(String tag, boolean value) { + this.context().setTag(tag, (Object) value); + return thisInstance(); + } + + + /* (non-Javadoc) + * @see io.opentracing.BaseSpan#setTag(java.lang.String, java.lang.Number) + */ + @Override + public final S setTag(String tag, Number value) { + this.context().setTag(tag, (Object) value); + return thisInstance(); + } + + + /* (non-Javadoc) + * @see io.opentracing.BaseSpan#context() + */ + @Override + public final DDSpanContext context() { + return this.context; + } + + /* (non-Javadoc) + * @see io.opentracing.BaseSpan#getBaggageItem(java.lang.String) + */ + @Override + public final String getBaggageItem(String key) { + return this.context.getBaggageItem(key); + } + + /* (non-Javadoc) + * @see io.opentracing.BaseSpan#setBaggageItem(java.lang.String, java.lang.String) + */ + @Override + public final S setBaggageItem(String key, String value) { + this.context.setBaggageItem(key, value); + return thisInstance(); + } + + /* (non-Javadoc) + * @see io.opentracing.BaseSpan#setOperationName(java.lang.String) + */ + @Override + public final S setOperationName(String operationName) { + this.context().setOperationName(operationName); + return thisInstance(); + } + + /* (non-Javadoc) + * @see io.opentracing.BaseSpan#log(java.util.Map) + */ + @Override + public final S log(Map map) { + logger.debug("`log` method is not implemented. Doing nothing"); + return thisInstance(); + } + + /* (non-Javadoc) + * @see io.opentracing.BaseSpan#log(long, java.util.Map) + */ + @Override + public final S log(long l, Map map) { + logger.debug("`log` method is not implemented. Doing nothing"); + return thisInstance(); + } + + /* (non-Javadoc) + * @see io.opentracing.BaseSpan#log(java.lang.String) + */ + @Override + public final S log(String s) { + logger.debug("`log` method is not implemented. Provided log: {}",s); + return thisInstance(); + } + + /* (non-Javadoc) + * @see io.opentracing.BaseSpan#log(long, java.lang.String) + */ + @Override + public final S log(long l, String s) { + logger.debug("`log` method is not implemented. Provided log: {}",s); + return thisInstance(); + } + + + /* (non-Javadoc) + * @see io.opentracing.BaseSpan#log(java.lang.String, java.lang.Object) + */ + @Override + public final S log(String s, Object o) { + logger.debug("`log` method is not implemented. Provided log: {}",s); + return thisInstance(); + } + + /* (non-Javadoc) + * @see io.opentracing.BaseSpan#log(long, java.lang.String, java.lang.Object) + */ + @Override + public final S log(long l, String s, Object o) { + logger.debug("`log` method is not implemented. Provided log: {}",s); + return thisInstance(); + } + + public final S setServiceName(String serviceName) { + this.context().setServiceName(serviceName); + return thisInstance(); + } + + public final S setResourceName(String resourceName) { + this.context().setResourceName(resourceName); + return thisInstance(); + } + + public final S setSpanType(String type) { + this.context().setSpanType(type); + return thisInstance(); + } + + protected abstract S thisInstance(); + + //Getters and JSON serialisation instructions + + /** + * Meta merges baggage and tags (stringified values) + * + * @return merged context baggage and tags + */ + @JsonGetter + public Map getMeta() { + Map meta = new HashMap(); + for (Entry entry : context().getBaggageItems().entrySet()) { + meta.put(entry.getKey(), entry.getValue()); + } + for (Entry entry : getTags().entrySet()) { + meta.put(entry.getKey(), String.valueOf(entry.getValue())); + } + return meta; + } + + @JsonGetter("start") + public long getStartTime() { + return startTimeMicro * 1000L; + } + + @JsonGetter("duration") + public long getDurationNano() { + return durationNano; + } + + @JsonGetter("service") + public String getServiceName() { + return context.getServiceName(); + } + + @JsonGetter("trace_id") + public long getTraceId() { + return context.getTraceId(); + } + + @JsonGetter("span_id") + public long getSpanId() { + return context.getSpanId(); + } + + @JsonGetter("parent_id") + public long getParentId() { + return context.getParentId(); + } + + @JsonGetter("resource") + public String getResourceName() { + return context.getResourceName(); + } + + @JsonGetter("name") + public String getOperationName() { + return context.getOperationName(); + } + + @JsonIgnore + public Map getTags() { + return this.context().getTags(); + } + @JsonGetter + public String getType() { + return context.getSpanType(); + } + + @JsonGetter + public int getError() { + return context.getErrorFlag() ? 1 : 0; + } + + @Override + public String toString() { + return context.toString(); + } +} diff --git a/dd-trace/src/main/java/com/datadoghq/trace/DDSpan.java b/dd-trace/src/main/java/com/datadoghq/trace/DDSpan.java index 9e1b87610b..0845e105f4 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/DDSpan.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/DDSpan.java @@ -1,16 +1,6 @@ package com.datadoghq.trace; -import com.fasterxml.jackson.annotation.JsonGetter; -import com.fasterxml.jackson.annotation.JsonIgnore; import io.opentracing.Span; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.TimeUnit; /** * Represents an in-flight span in the opentracing system. @@ -18,27 +8,7 @@ import java.util.concurrent.TimeUnit; *

Spans are created by the {@link DDTracer#buildSpan}. * This implementation adds some features according to the DD agent. */ -public class DDSpan implements io.opentracing.Span { - - - /** - * StartTime stores the creation time of the span in milliseconds - */ - private long startTimeMicro; - /** - * StartTimeNano stores the only the nanoseconds for more accuracy - */ - private long startTimeNano; - /** - * The duration in nanoseconds computed using the startTimeMicro and startTimeNano - */ - private long durationNano; - /** - * The context attached to the span - */ - private final DDSpanContext context; - - private final static Logger logger = LoggerFactory.getLogger(DDSpan.class); +public class DDSpan extends DDBaseSpan implements Span { /** * A simple constructor. @@ -50,276 +20,12 @@ public class DDSpan implements io.opentracing.Span { protected DDSpan( long timestampMicro, DDSpanContext context) { - - this.context = context; - - // record the start time in nano (current milli + nano delta) - if (timestampMicro == 0L) { - this.startTimeMicro = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()); - } else { - this.startTimeMicro = timestampMicro; - } - this.startTimeNano = System.nanoTime(); - - // track each span of the trace - this.context.getTrace().add(this); - - } - - /* (non-Javadoc) - * @see io.opentracing.Span#finish() - */ - public void finish() { - this.durationNano = System.nanoTime() - startTimeNano; - afterFinish(); - } - - /* (non-Javadoc) - * @see io.opentracing.Span#finish(long) - */ - public void finish(long stoptimeMicros) { - this.durationNano = TimeUnit.MICROSECONDS.toNanos(stoptimeMicros - this.startTimeMicro); - afterFinish(); - } - - /** - * Close the span. If the current span is the parent, check if each child has also been closed - * If not, warned it - */ - protected void afterFinish() { - logger.debug("{} - Closing the span.", this); - - // warn if one of the parent's children is not finished - if (this.isRootSpan()) { - List spans = this.context.getTrace(); - - for (Span span : spans) { - if (((DDSpan) span).getDurationNano() == 0L) { - logger.warn("{} - The parent span is marked as finished but this span isn't. You have to close each children.", this); - } - } - this.context.getTracer().write(this.context.getTrace()); - logger.debug("{} - Write the trace", this); - } - } - - /* (non-Javadoc) - * @see io.opentracing.Span#close() - */ - public void close() { - this.finish(); - } - - /** - * Check if the span is the root parent. It means that the traceId is the same as the spanId - * - * @return true if root, false otherwise - */ - private boolean isRootSpan() { - - if (context().getTrace().isEmpty()) { - return false; - } - // First item of the array AND tracer set - DDSpan first = (DDSpan) context().getTrace().get(0); - return first.context.getSpanId() == this.context.getSpanId() && this.context.getTracer() != null; - } - - /* (non-Javadoc) - * @see io.opentracing.Span#setTag(java.lang.String, java.lang.String) - */ - public Span setTag(String tag, String value) { - this.context().setTag(tag, (Object) value); - return this; - } - - /* (non-Javadoc) - * @see io.opentracing.Span#setTag(java.lang.String, boolean) - */ - public Span setTag(String tag, boolean value) { - this.context().setTag(tag, (Object) value); - return this; - } - - /* (non-Javadoc) - * @see io.opentracing.Span#setTag(java.lang.String, java.lang.Number) - */ - public Span setTag(String tag, Number value) { - this.context().setTag(tag, (Object) value); - return this; + super(timestampMicro,context); } - /* (non-Javadoc) - * @see io.opentracing.Span#context() - */ - public DDSpanContext context() { - return this.context; - } - - /* (non-Javadoc) - * @see io.opentracing.Span#setBaggageItem(java.lang.String, java.lang.String) - */ - public Span setBaggageItem(String key, String value) { - this.context.setBaggageItem(key, value); - return this; - } - - /* (non-Javadoc) - * @see io.opentracing.Span#getBaggageItem(java.lang.String) - */ - public String getBaggageItem(String key) { - return this.context.getBaggageItem(key); - } - - /* (non-Javadoc) - * @see io.opentracing.Span#setOperationName(java.lang.String) - */ - public Span setOperationName(String operationName) { - this.context().setOperationName(operationName); - return this; - } - - /* (non-Javadoc) - * @see io.opentracing.Span#log(java.lang.String, java.lang.Object) - */ - public Span log(Map map) { - logger.debug("`log` method is not implemented. Doing nothing"); - return this; - } - - /* (non-Javadoc) - * @see io.opentracing.Span#log(java.lang.String, java.lang.Object) - */ - public Span log(long l, Map map) { - logger.debug("`log` method is not implemented. Doing nothing"); - return this; - } - - /* (non-Javadoc) - * @see io.opentracing.Span#log(java.lang.String, java.lang.Object) - */ - public Span log(String s) { - logger.debug("`log` method is not implemented. Provided log: {}",s); - return this; - } - - /* (non-Javadoc) - * @see io.opentracing.Span#log(java.lang.String, java.lang.Object) - */ - public Span log(long l, String s) { - logger.debug("`log` method is not implemented. Provided log: {}",s); - return this; - } - - /* (non-Javadoc) - * @see io.opentracing.Span#log(java.lang.String, java.lang.Object) - */ - public Span log(String s, Object o) { - logger.debug("`log` method is not implemented. Provided log: {}",s); - return this; - } - - /* (non-Javadoc) - * @see io.opentracing.Span#log(long, java.lang.String, java.lang.Object) - */ - public Span log(long l, String s, Object o) { - logger.debug("`log` method is not implemented. Provided log: {}",s); - return this; - } - - - //Getters and JSON serialisation instructions - - /** - * Meta merges baggage and tags (stringified values) - * - * @return merged context baggage and tags - */ - @JsonGetter - public Map getMeta() { - Map meta = new HashMap(); - for (Entry entry : context().getBaggageItems().entrySet()) { - meta.put(entry.getKey(), entry.getValue()); - } - for (Entry entry : getTags().entrySet()) { - meta.put(entry.getKey(), String.valueOf(entry.getValue())); - } - return meta; - } - - @JsonGetter("start") - public long getStartTime() { - return startTimeMicro * 1000L; - } - - @JsonGetter("duration") - public long getDurationNano() { - return durationNano; - } - - @JsonGetter("service") - public String getServiceName() { - return context.getServiceName(); - } - - @JsonGetter("trace_id") - public long getTraceId() { - return context.getTraceId(); - } - - @JsonGetter("span_id") - public long getSpanId() { - return context.getSpanId(); - } - - @JsonGetter("parent_id") - public long getParentId() { - return context.getParentId(); - } - - @JsonGetter("resource") - public String getResourceName() { - return context.getResourceName(); - } - - @JsonGetter("name") - public String getOperationName() { - return context.getOperationName(); - } - - @JsonIgnore - public Map getTags() { - return this.context().getTags(); - } - @JsonGetter - public String getType() { - return context.getSpanType(); - } - - @JsonGetter - public int getError() { - return context.getErrorFlag() ? 1 : 0; - } - - @Override - public String toString() { - return context.toString(); - } - - - public Span setServiceName(String serviceName) { - this.context().setServiceName(serviceName); - return this; - } - - public Span setResourceName(String resourceName) { - this.context().setResourceName(resourceName); - return this; - } - - public Span setSpanType(String type) { - this.context().setSpanType(type); - return this; - } + @Override + protected DDSpan thisInstance() { + return this; + } } diff --git a/dd-trace/src/main/java/com/datadoghq/trace/DDSpanContext.java b/dd-trace/src/main/java/com/datadoghq/trace/DDSpanContext.java index 8c1dc7b5f5..645021744b 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/DDSpanContext.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/DDSpanContext.java @@ -1,12 +1,16 @@ package com.datadoghq.trace; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import com.datadoghq.trace.integration.DDSpanContextDecorator; import com.fasterxml.jackson.annotation.JsonIgnore; -import io.opentracing.Span; -import io.opentracing.tag.Tags; -import java.util.*; +import io.opentracing.tag.Tags; /** * SpanContext represents Span state that must propagate to descendant Spans and across process boundaries. @@ -44,7 +48,7 @@ public class DDSpanContext implements io.opentracing.SpanContext { /** * The collection of all span related to this one */ - private final List trace; + private final List> trace; /** * Each span have an operation name describing the current span */ @@ -70,7 +74,7 @@ public class DDSpanContext implements io.opentracing.SpanContext { boolean errorFlag, String spanType, Map tags, - List trace, + List> trace, DDTracer tracer) { this.traceId = traceId; @@ -93,7 +97,7 @@ public class DDSpanContext implements io.opentracing.SpanContext { this.tags = tags; if (trace == null) { - this.trace = new ArrayList(); + this.trace = new ArrayList>(); } else { this.trace = trace; } @@ -156,7 +160,7 @@ public class DDSpanContext implements io.opentracing.SpanContext { } @JsonIgnore - public List getTrace() { + public List> getTrace() { return this.trace; } diff --git a/dd-trace/src/main/java/com/datadoghq/trace/DDTracer.java b/dd-trace/src/main/java/com/datadoghq/trace/DDTracer.java index 778b95d4da..835c08737f 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/DDTracer.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/DDTracer.java @@ -1,5 +1,14 @@ package com.datadoghq.trace; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.datadoghq.trace.integration.DDSpanContextDecorator; import com.datadoghq.trace.propagation.Codec; import com.datadoghq.trace.propagation.HTTPCodec; @@ -7,13 +16,12 @@ import com.datadoghq.trace.sampling.AllSampler; import com.datadoghq.trace.sampling.Sampler; import com.datadoghq.trace.writer.DDAgentWriter; import com.datadoghq.trace.writer.Writer; + +import io.opentracing.ActiveSpan; +import io.opentracing.BaseSpan; import io.opentracing.Span; import io.opentracing.SpanContext; import io.opentracing.propagation.Format; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; /** @@ -132,11 +140,11 @@ public class DDTracer implements io.opentracing.Tracer { * * @param trace a list of the spans related to the same trace */ - public void write(List trace) { + public void write(List> trace) { if (trace.isEmpty()) { return; } - if (this.sampler.sample((DDSpan) trace.get(0))) { + if (this.sampler.sample(trace.get(0))) { this.writer.write(trace); } } @@ -144,6 +152,48 @@ public class DDTracer implements io.opentracing.Tracer { public void close() { writer.close(); } + + private final ThreadLocal currentActiveSpan = new ThreadLocal(); + + @Override + public DDActiveSpan activeSpan() { + return currentActiveSpan.get(); + } + + /** + * Set the newly created active span as the active one from the Tracer's perspective + * + * @param activeSpan + */ + protected void makeActive(DDActiveSpan activeSpan){ + currentActiveSpan.set(activeSpan); + } + + /** + * Deactivate the current span (if active) and make the parent active (again) + * + * @param activeSpan + */ + protected void deactivate(DDActiveSpan activeSpan){ + DDActiveSpan current = activeSpan(); + if(current==activeSpan){ + //The parent becomes the active span + makeActive(activeSpan.getParent()); + } + } + + @Override + public ActiveSpan makeActive(Span span) { + if(!(span instanceof DDSpan)) + throw new IllegalArgumentException("Cannot transform a non DDSpan into a DDActiveSpan. Provided class: "+span.getClass()); + + //Wrap the provided manual span into an active one with the current parent + DDActiveSpan activeSpan = new DDActiveSpan(activeSpan(),(DDSpan)span); + + makeActive(activeSpan); + + return activeSpan; + } /** * Spans are built using this builder @@ -163,29 +213,53 @@ public class DDTracer implements io.opentracing.Tracer { private String resourceName; private boolean errorFlag; private String spanType; + private boolean ignoreActiveSpan = false; - /** - * This method actually build the span according to the builder settings - * DD-Agent requires a serviceName. If it has not been provided, the method will throw a RuntimeException - * - * @return An fresh span - */ - public DDSpan start() { + @Override + public SpanBuilder ignoreActiveSpan() { + this.ignoreActiveSpan = true; + return this; + } - // build the context - DDSpanContext context = buildSpanContext(); - DDSpan span = new DDSpan(this.timestamp, context); - - logger.debug("{} - Starting a new span.", span); + @Override + public DDActiveSpan startActive() { + //Set the active span as parent if ignoreActiveSpan==true + DDActiveSpan activeParent = null; + if(!ignoreActiveSpan){ + DDActiveSpan current = activeSpan(); + if(current!=null){ + activeParent = current; + } + } + + //Create the active span + DDActiveSpan activeSpan = new DDActiveSpan(activeParent,this.timestamp, buildSpanContext()); + logger.debug("{} - Starting a new active span.", activeSpan); + + makeActive(activeSpan); + + return activeSpan; + } + @Override + public DDSpan startManual() { + DDSpan span = new DDSpan(this.timestamp, buildSpanContext()); + logger.debug("{} - Starting a new manuel span.", span); return span; } + @Override + @Deprecated + public DDSpan start() { + return startManual(); + } + @Override public DDTracer.DDSpanBuilder withTag(String tag, Number number) { return withTag(tag, (Object) number); } + @Override public DDTracer.DDSpanBuilder withTag(String tag, String string) { if (tag.equals(DDTags.SERVICE_NAME)) { return withServiceName(string); @@ -198,15 +272,17 @@ public class DDTracer implements io.opentracing.Tracer { } } + @Override public DDTracer.DDSpanBuilder withTag(String tag, boolean bool) { return withTag(tag, (Object) bool); } + public DDSpanBuilder(String operationName) { this.operationName = operationName; } - + @Override public DDTracer.DDSpanBuilder withStartTimestamp(long timestampMillis) { this.timestamp = timestampMillis; return this; @@ -239,15 +315,18 @@ public class DDTracer implements io.opentracing.Tracer { return parent.baggageItems(); } - public DDTracer.DDSpanBuilder asChildOf(Span span) { + @Override + public DDTracer.DDSpanBuilder asChildOf(BaseSpan span) { return asChildOf(span == null ? null : span.context()); } + @Override public DDTracer.DDSpanBuilder asChildOf(SpanContext spanContext) { this.parent = spanContext; return this; } + @Override public DDTracer.DDSpanBuilder addReference(String referenceType, SpanContext spanContext) { logger.debug("`addReference` method is not implemented. Doing nothing"); return this; @@ -301,18 +380,18 @@ public class DDTracer implements io.opentracing.Tracer { // some attributes are inherited from the parent context = new DDSpanContext( this.parent == null ? generatedId : p.getTraceId(), - generatedId, - this.parent == null ? 0L : p.getSpanId(), - serviceName, - operationName, - this.resourceName, - this.parent == null ? null : p.getBaggageItems(), - errorFlag, - spanType, - this.tags, - this.parent == null ? null : p.getTrace(), - DDTracer.this - ); + generatedId, + this.parent == null ? 0L : p.getSpanId(), + serviceName, + operationName, + this.resourceName, + this.parent == null ? null : p.getBaggageItems(), + errorFlag, + spanType, + this.tags, + this.parent == null ? null : p.getTrace(), + DDTracer.this + ); return context; } diff --git a/dd-trace/src/main/java/com/datadoghq/trace/sampling/ASampler.java b/dd-trace/src/main/java/com/datadoghq/trace/sampling/ASampler.java index 8b674cfc74..38d00be2b0 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/sampling/ASampler.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/sampling/ASampler.java @@ -5,9 +5,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.regex.Pattern; -import com.datadoghq.trace.DDSpan; - -import io.opentracing.Span; +import com.datadoghq.trace.DDBaseSpan; public abstract class ASampler implements Sampler{ @@ -15,28 +13,25 @@ public abstract class ASampler implements Sampler{ * Sample tags */ protected Map skipTagsPatterns = new HashMap(); - + @Override - public boolean sample(Span span) { - if(span instanceof DDSpan){ - DDSpan ddSpan = (DDSpan) span; - - //Filter by tag values - for(Entry entry: skipTagsPatterns.entrySet()){ - Object value = ddSpan.getTags().get(entry.getKey()); - if(value != null){ - String strValue = String.valueOf(value); - Pattern skipPattern = entry.getValue(); - if(skipPattern.matcher(strValue).matches()){ - return false; - } + public boolean sample(DDBaseSpan span) { + + //Filter by tag values + for(Entry entry: skipTagsPatterns.entrySet()){ + Object value = span.getTags().get(entry.getKey()); + if(value != null){ + String strValue = String.valueOf(value); + Pattern skipPattern = entry.getValue(); + if(skipPattern.matcher(strValue).matches()){ + return false; } } } - + return doSample(span); } - + /** * Pattern based skipping of tag values * @@ -46,7 +41,7 @@ public abstract class ASampler implements Sampler{ public void addSkipTagPattern(String tag,Pattern skipPattern){ skipTagsPatterns.put(tag, skipPattern); } - - protected abstract boolean doSample(Span span); + + protected abstract boolean doSample(DDBaseSpan span); } diff --git a/dd-trace/src/main/java/com/datadoghq/trace/sampling/AllSampler.java b/dd-trace/src/main/java/com/datadoghq/trace/sampling/AllSampler.java index af8cb7d756..25bd06e8fe 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/sampling/AllSampler.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/sampling/AllSampler.java @@ -1,6 +1,6 @@ package com.datadoghq.trace.sampling; -import io.opentracing.Span; +import com.datadoghq.trace.DDBaseSpan; /** * Sampler that always says yes... @@ -8,7 +8,7 @@ import io.opentracing.Span; public class AllSampler extends ASampler { @Override - public boolean doSample(Span span) { + public boolean doSample(DDBaseSpan span) { return true; } diff --git a/dd-trace/src/main/java/com/datadoghq/trace/sampling/RateSampler.java b/dd-trace/src/main/java/com/datadoghq/trace/sampling/RateSampler.java index e96c02c959..48b718299e 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/sampling/RateSampler.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/sampling/RateSampler.java @@ -4,10 +4,9 @@ package com.datadoghq.trace.sampling; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.datadoghq.trace.DDBaseSpan; import com.google.auto.service.AutoService; -import io.opentracing.Span; - /** * This sampler sample the traces at a predefined rate. @@ -45,7 +44,7 @@ public class RateSampler extends ASampler { } @Override - public boolean doSample(Span span) { + public boolean doSample(DDBaseSpan span) { boolean sample = Math.random() <= this.sampleRate; logger.debug("{} - Span is sampled: {}", span, sample); return sample; diff --git a/dd-trace/src/main/java/com/datadoghq/trace/sampling/Sampler.java b/dd-trace/src/main/java/com/datadoghq/trace/sampling/Sampler.java index 16f6ed9208..29d158098c 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/sampling/Sampler.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/sampling/Sampler.java @@ -1,7 +1,7 @@ package com.datadoghq.trace.sampling; -import io.opentracing.Span; +import com.datadoghq.trace.DDBaseSpan; /** * Main interface to sample a collection of traces. @@ -14,6 +14,6 @@ public interface Sampler { * @param span the parent span with its context * @return true when the trace/spans has to be reported/written */ - boolean sample(Span span); + boolean sample(DDBaseSpan span); } diff --git a/dd-trace/src/main/java/com/datadoghq/trace/writer/DDAgentWriter.java b/dd-trace/src/main/java/com/datadoghq/trace/writer/DDAgentWriter.java index 6cd53fc93c..92687b9e1a 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/writer/DDAgentWriter.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/writer/DDAgentWriter.java @@ -1,14 +1,19 @@ package com.datadoghq.trace.writer; -import io.opentracing.Span; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.auto.service.AutoService; - import java.util.ArrayList; import java.util.List; -import java.util.concurrent.*; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.datadoghq.trace.DDBaseSpan; +import com.google.auto.service.AutoService; /** * This writer write provided traces to the a DD agent which is most of time located on the same host. @@ -45,7 +50,7 @@ public class DDAgentWriter implements Writer { /** * In memory collection of traces waiting for departure */ - private final BlockingQueue> traces; + private final BlockingQueue>> traces; /** * Async worker that posts the spans to the DD agent @@ -66,13 +71,13 @@ public class DDAgentWriter implements Writer { this.api = api; tokens = new Semaphore(DEFAULT_MAX_SPANS); - traces = new ArrayBlockingQueue>(DEFAULT_MAX_SPANS); + traces = new ArrayBlockingQueue>>(DEFAULT_MAX_SPANS); } /* (non-Javadoc) * @see com.datadoghq.trace.Writer#write(java.util.List) */ - public void write(List trace) { + public void write(List> trace) { //Try to add a new span in the queue boolean proceed = tokens.tryAcquire(trace.size()); @@ -111,10 +116,10 @@ public class DDAgentWriter implements Writer { public void run() { while (true) { try { - List> payload = new ArrayList>(); + List>> payload = new ArrayList>>(); //WAIT until a new span comes - List l = DDAgentWriter.this.traces.take(); + List> l = DDAgentWriter.this.traces.take(); payload.add(l); //Drain all spans up to a certain batch suze @@ -126,7 +131,7 @@ public class DDAgentWriter implements Writer { //Compute the number of spans sent int spansCount = 0; - for (List trace : payload) { + for (List> trace : payload) { spansCount += trace.size(); } logger.debug("Async writer just sent {} spans through {} traces", spansCount, payload.size()); diff --git a/dd-trace/src/main/java/com/datadoghq/trace/writer/DDApi.java b/dd-trace/src/main/java/com/datadoghq/trace/writer/DDApi.java index 1c10f950ed..21df592c8f 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/writer/DDApi.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/writer/DDApi.java @@ -8,12 +8,11 @@ import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.datadoghq.trace.DDBaseSpan; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.ObjectMapper; -import io.opentracing.Span; - /** * The API pointing to a DD agent */ @@ -41,7 +40,7 @@ public class DDApi { * @param traces the traces to be sent * @return the staus code returned */ - public boolean sendTraces(List> traces) { + public boolean sendTraces(List>> traces) { int status = callPUT(tracesEndpoint, traces); if (status == 200) { logger.debug("Succesfully sent {} traces to the DD agent.", traces.size()); diff --git a/dd-trace/src/main/java/com/datadoghq/trace/writer/LoggingWriter.java b/dd-trace/src/main/java/com/datadoghq/trace/writer/LoggingWriter.java index 8611028027..929008f775 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/writer/LoggingWriter.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/writer/LoggingWriter.java @@ -5,17 +5,16 @@ import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.datadoghq.trace.DDBaseSpan; import com.google.auto.service.AutoService; -import io.opentracing.Span; - @AutoService(Writer.class) public class LoggingWriter implements Writer{ private static final Logger logger = LoggerFactory.getLogger(LoggingWriter.class.getName()); @Override - public void write(List trace) { + public void write(List> trace) { logger.info("write(trace): {}", trace); } diff --git a/dd-trace/src/main/java/com/datadoghq/trace/writer/Writer.java b/dd-trace/src/main/java/com/datadoghq/trace/writer/Writer.java index 969954f8b1..2fd8ae7af8 100644 --- a/dd-trace/src/main/java/com/datadoghq/trace/writer/Writer.java +++ b/dd-trace/src/main/java/com/datadoghq/trace/writer/Writer.java @@ -2,7 +2,7 @@ package com.datadoghq.trace.writer; import java.util.List; -import io.opentracing.Span; +import com.datadoghq.trace.DDBaseSpan; /** * A writer is responsible to send collected spans to some place @@ -14,7 +14,7 @@ public interface Writer { * * @param trace the list of spans to write */ - void write(List trace); + void write(List> trace); /** * Start the writer diff --git a/dd-trace/src/test/java/com/datadoghq/trace/DDSpanBuilderTest.java b/dd-trace/src/test/java/com/datadoghq/trace/DDSpanBuilderTest.java index 75355be240..06ea01a704 100644 --- a/dd-trace/src/test/java/com/datadoghq/trace/DDSpanBuilderTest.java +++ b/dd-trace/src/test/java/com/datadoghq/trace/DDSpanBuilderTest.java @@ -131,9 +131,7 @@ public class DDSpanBuilderTest { final long expectedParentId = spanId; DDSpanContext mockedContext = mock(DDSpanContext.class); - DDSpan mockedSpan = mock(DDSpan.class); - - when(mockedSpan.context()).thenReturn(mockedContext); + when(mockedContext.getSpanId()).thenReturn(spanId); when(mockedContext.getServiceName()).thenReturn("foo"); @@ -142,13 +140,12 @@ public class DDSpanBuilderTest { DDSpan span = tracer .buildSpan(expectedName) .withServiceName("foo") - .asChildOf(mockedSpan) + .asChildOf(mockedContext) .start(); DDSpanContext actualContext = span.context(); assertThat(actualContext.getParentId()).isEqualTo(expectedParentId); - } diff --git a/dd-trace/src/test/java/com/datadoghq/trace/DDTracerTest.java b/dd-trace/src/test/java/com/datadoghq/trace/DDTracerTest.java index 691cd5e4fb..866eddcd73 100644 --- a/dd-trace/src/test/java/com/datadoghq/trace/DDTracerTest.java +++ b/dd-trace/src/test/java/com/datadoghq/trace/DDTracerTest.java @@ -16,6 +16,7 @@ import com.datadoghq.trace.DDTracer; import com.datadoghq.trace.sampling.RateSampler; import com.datadoghq.trace.writer.Writer; +import io.opentracing.BaseSpan; import io.opentracing.Span; @@ -34,7 +35,7 @@ public class DDTracerTest { .thenReturn(true) .thenReturn(false); - List spans = new ArrayList(); + List> spans = new ArrayList>(); spans.add(span); spans.add(span); spans.add(span); diff --git a/dd-trace/src/test/java/com/datadoghq/trace/writer/impl/DDAgentWriterTest.java b/dd-trace/src/test/java/com/datadoghq/trace/writer/impl/DDAgentWriterTest.java index f5da256de7..80edb06638 100644 --- a/dd-trace/src/test/java/com/datadoghq/trace/writer/impl/DDAgentWriterTest.java +++ b/dd-trace/src/test/java/com/datadoghq/trace/writer/impl/DDAgentWriterTest.java @@ -11,6 +11,7 @@ import java.util.List; import org.junit.Before; import org.junit.Test; +import com.datadoghq.trace.DDBaseSpan; import com.datadoghq.trace.DDSpan; import com.datadoghq.trace.DDTracer; import com.datadoghq.trace.writer.DDAgentWriter; @@ -22,7 +23,7 @@ public class DDAgentWriterTest { DDSpan parent = null; DDApi mockedAPI = null; - List> traces = new ArrayList>(); + List>> traces = new ArrayList>>(); DDAgentWriter ddAgentWriter = null; @Before diff --git a/pom.xml b/pom.xml index fcaf284a05..8a5f3038b2 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ - 0.22.0 + 0.30.0 1.7