Thread safe implementation of Tags + added SpanContext decorators
MODIFY
src/main/java/com/datadoghq/trace/impl/DDSpan.java
src/main/java/com/datadoghq/trace/impl/DDSpan.java
@@ -196,7 +196,7 @@ public class DDSpan implements io.opentracing.Span {
* @see io.opentracing.Span#log(java.lang.String, java.lang.Object)
*/
public Span log(String s) {
- logger.debug("`log` method is not implemented. Doing nothing");
+ logger.debug("`log` method is not implemented. Provided log: {}",s);
return this;
}
@@ -204,7 +204,7 @@ public class DDSpan implements io.opentracing.Span {
* @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. Doing nothing");
+ logger.debug("`log` method is not implemented. Provided log: {}",s);
return this;
}
@@ -212,7 +212,7 @@ public class DDSpan implements io.opentracing.Span {
* @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. Doing nothing");
+ logger.debug("`log` method is not implemented. Provided log: {}",s);
return this;
}
@@ -220,7 +220,7 @@ public class DDSpan implements io.opentracing.Span {
* @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. Doing nothing");
+ logger.debug("`log` method is not implemented. Provided log: {}",s);
return this;
}
@@ -314,8 +314,8 @@ public class DDSpan implements io.opentracing.Span {
return this;
}
- public Span setType(String type) {
- this.context().setType(type);
+ public Span setSpanType(String type) {
+ this.context().setSpanType(type);
return this;
}
}

MODIFY
src/main/java/com/datadoghq/trace/impl/DDSpanContext.java
src/main/java/com/datadoghq/trace/impl/DDSpanContext.java
package com.datadoghq.trace.impl;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -76,7 +80,7 @@ public class DDSpanContext implements io.opentracing.SpanContext {
this.parentId = parentId;
if (baggageItems == null) {
- this.baggageItems = Collections.emptyMap();
+ this.baggageItems = new HashMap<String, String>();
} else {
this.baggageItems = baggageItems;
}
@@ -128,9 +132,6 @@ public class DDSpanContext implements io.opentracing.SpanContext {
}
public void setBaggageItem(String key, String value) {
- if (this.baggageItems.isEmpty()) {
- this.baggageItems = new HashMap<String, String>();
- }
this.baggageItems.put(key, value);
}
@@ -166,11 +167,20 @@ public class DDSpanContext implements io.opentracing.SpanContext {
* @param value the value of the value
* @return the builder instance
*/
- public void setTag(String tag, Object value) {
+ public synchronized void setTag(String tag, Object value) {
if (this.tags.isEmpty()) {
this.tags = new HashMap<String, Object>();
}
this.tags.put(tag, value);
+
+ //Call decorators
+ for(DDSpanContextDecorator decorator:tracer.getSpanContextDecorators()){
+ decorator.afterSetTag(this, tag, value);
+ }
+ }
+
+ public synchronized Map<String, Object> getTags() {
+ return Collections.unmodifiableMap(tags);
}
@Override
@@ -188,10 +198,6 @@ public class DDSpanContext implements io.opentracing.SpanContext {
return operationName;
}
- public Map<String, Object> getTags() {
- return tags;
- }
-
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
@@ -200,7 +206,7 @@ public class DDSpanContext implements io.opentracing.SpanContext {
this.resourceName = resourceName;
}
- public void setType(String type) {
- this.spanType = type;
+ public void setSpanType(String spanType) {
+ this.spanType = spanType;
}
}

ADD
src/main/java/com/datadoghq/trace/impl/DDSpanContextDecorator.java
+package com.datadoghq.trace.impl;
+
+/**
+ * Span decorators are called when new tags are written and proceed to various remappings and enrichments
+ */
+public interface DDSpanContextDecorator {
+
+ /**
+ * A tag was just added to the context. The decorator provides a way to enrich the context a bit more.
+ *
+ * @param context the target context to decorate
+ * @param tag The tag set
+ * @param value the value assigned to the tag
+ */
+ public void afterSetTag(DDSpanContext context , String tag, Object value);
+
+}
\ No newline at end of file

MODIFY
src/main/java/com/datadoghq/trace/impl/DDTracer.java
src/main/java/com/datadoghq/trace/impl/DDTracer.java
package com.datadoghq.trace.impl;
+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.Sampler;
import com.datadoghq.trace.Writer;
import com.datadoghq.trace.writer.impl.LoggingWritter;
+
import io.opentracing.Span;
import io.opentracing.SpanContext;
import io.opentracing.propagation.Format;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.*;
/**
* DDTracer makes it easy to send traces and span to DD using the OpenTracing instrumentation.
@@ -25,6 +31,11 @@ public class DDTracer implements io.opentracing.Tracer {
*/
private final Sampler sampler;
+ /**
+ * Span context decorators
+ */
+ private final List<DDSpanContextDecorator> spanContextDecorators = new ArrayList<DDSpanContextDecorator>();
+
private final static Logger logger = LoggerFactory.getLogger(DDTracer.class);
@@ -40,6 +51,25 @@ public class DDTracer implements io.opentracing.Tracer {
this.sampler = sampler;
}
+
+ /**
+ * Returns the list of span context decorators
+ *
+ * @return the list of span context decorators
+ */
+ public List<DDSpanContextDecorator> getSpanContextDecorators() {
+ return Collections.unmodifiableList(spanContextDecorators);
+ }
+
+ /**
+ * Add a new decorator in the list ({@link DDSpanContextDecorator})
+ *
+ * @param decorator The decorator in the list
+ */
+ public void addDecorator(DDSpanContextDecorator decorator){
+ spanContextDecorators.add(decorator);
+ }
+
public DDSpanBuilder buildSpan(String operationName) {
return new DDSpanBuilder(operationName);
}
@@ -219,7 +249,7 @@ public class DDTracer implements io.opentracing.Tracer {
serviceName,
this.operationName,
this.resourceName,
- this.parent == null ? Collections.<String, String>emptyMap() : p.getBaggageItems(),
+ this.parent == null ? new HashMap<String, String>() : p.getBaggageItems(),
errorFlag,
spanType,
this.tags,

ADD
src/main/java/com/datadoghq/trace/impl/MapperDecorator.java
+package com.datadoghq.trace.impl;
+
+import java.util.Map;
+
+/**
+ * Remap some tags to other tags
+ */
+public class MapperDecorator implements DDSpanContextDecorator {
+
+ public static final String SPAN_TYPE = "spanType";
+ public static final String SERVICE_NAME = "serviceName";
+ public static final String RESOURCE_NAME = "resourceName";
+
+ private final Map<String,String> mappings;
+
+ public MapperDecorator(Map<String, String> mappings) {
+ super();
+ this.mappings = mappings;
+ }
+
+ @Override
+ public void afterSetTag(DDSpanContext context, String tag, Object value) {
+ String toAssign = mappings.get(tag);
+ if(toAssign != null){
+ if(toAssign.equals(SPAN_TYPE)){
+ context.setSpanType(String.valueOf(value));
+ }else if(toAssign.equals(SERVICE_NAME)){
+ context.setServiceName(String.valueOf(value));
+ }else if(toAssign.equals(RESOURCE_NAME)){
+ context.setResourceName(String.valueOf(value));
+ }else{
+ //General remap
+ context.setTag(toAssign, value);
+ }
+ }
+ }
+
+}

MODIFY
src/test/java/com/datadoghq/trace/impl/DDSpanTest.java
src/test/java/com/datadoghq/trace/impl/DDSpanTest.java
package com.datadoghq.trace.impl;
-import org.junit.Test;
+import static org.assertj.core.api.Assertions.assertThat;
import java.util.Collections;
-import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.Test;
public class DDSpanTest {
@@ -44,7 +44,7 @@ public class DDSpanTest {
assertThat(span.getResourceName()).isEqualTo(expected);
expected = "type";
- span.setType(expected);
+ span.setSpanType(expected);
assertThat(span.getType()).isEqualTo(expected);
}

Thread safe implementation of Tags + added SpanContext decorators