Ability to add extra service information (WIP)
MODIFY
dd-trace/src/main/java/com/datadoghq/trace/DDTracer.java
dd-trace/src/main/java/com/datadoghq/trace/DDTracer.java
@@ -7,13 +7,19 @@ import com.datadoghq.trace.sampling.AllSampler;
import com.datadoghq.trace.sampling.Sampler;
import com.datadoghq.trace.writer.LoggingWriter;
import com.datadoghq.trace.writer.Writer;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import io.opentracing.ActiveSpan;
import io.opentracing.ActiveSpanSource;
import io.opentracing.BaseSpan;
import io.opentracing.SpanContext;
import io.opentracing.propagation.Format;
import io.opentracing.util.ThreadLocalActiveSpanSource;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
import java.util.concurrent.ThreadLocalRandom;
import lombok.extern.slf4j.Slf4j;
@@ -37,6 +43,7 @@ public class DDTracer extends ThreadLocalActiveSpanSource implements io.opentrac
private final Map<String, List<AbstractDecorator>> spanContextDecorators = new HashMap<>();
private final CodecRegistry registry;
+ private final List<Service> services = new ArrayList<>();
/** Default constructor, trace/spans are logged, no trace/span dropped */
public DDTracer() {
@@ -137,6 +144,33 @@ public class DDTracer extends ThreadLocalActiveSpanSource implements io.opentrac
return "DDTracer{" + "writer=" + writer + ", sampler=" + sampler + '}';
}
+ /**
+ * Register additional information about a service. Service additional information are a Datadog
+ * feature only. Services are reported through a specific Datadog endpoint.
+ *
+ * @param service additional service information
+ */
+ public void addServiceInfo(final Service service) {
+ services.add(service);
+ // Update the write
+ try {
+ // We don't bother to send multiple times the list of services at this time
+ writer.writeServices(services);
+ } catch (final Throwable ex) {
+ log.warn("Failed to report additional service information, reason: {}", ex.getMessage());
+ }
+ }
+
+ /**
+ * Return the list of additional service information registered
+ *
+ * @return the list of additional service information
+ */
+ @JsonIgnore
+ public List<Service> getServiceInfo() {
+ return services;
+ }
+
private static class CodecRegistry {
private final Map<Format<?>, Codec<?>> codecs = new HashMap<>();

ADD
dd-trace/src/main/java/com/datadoghq/trace/Service.java
+package com.datadoghq.trace;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class Service {
+
+ private final String name;
+ private final String appName;
+ private final Service.AppType appType;
+
+ public Service(final String name, final String appName, final AppType appType) {
+ this.name = name;
+ this.appName = appName;
+ this.appType = appType;
+ }
+
+ @JsonProperty("service")
+ public String getName() {
+ return name;
+ }
+
+ @JsonProperty("app")
+ public String getAppName() {
+ return appName;
+ }
+
+ @JsonProperty("app_type")
+ public AppType getAppType() {
+ return appType;
+ }
+
+ public enum AppType {
+ WEB("web"),
+ DB("db"),
+ CUSTOM("custom");
+
+ private final String type;
+
+ AppType(final String type) {
+ this.type = type;
+ }
+
+ public String toString() {
+ return type;
+ }
+ }
+}

MODIFY
dd-trace/src/main/java/com/datadoghq/trace/writer/DDAgentWriter.java
dd-trace/src/main/java/com/datadoghq/trace/writer/DDAgentWriter.java
package com.datadoghq.trace.writer;
import com.datadoghq.trace.DDBaseSpan;
+import com.datadoghq.trace.Service;
import com.google.auto.service.AutoService;
import java.util.List;
import java.util.concurrent.Callable;
@@ -80,6 +81,9 @@ public class DDAgentWriter implements Writer {
queueFullReported = false;
}
+ @Override
+ public void writeServices(final List<Service> services) {}
+
/* (non-Javadoc)
* @see com.datadoghq.trace.writer.Writer#start()
*/

MODIFY
dd-trace/src/main/java/com/datadoghq/trace/writer/ListWriter.java
dd-trace/src/main/java/com/datadoghq/trace/writer/ListWriter.java
package com.datadoghq.trace.writer;
import com.datadoghq.trace.DDBaseSpan;
+import com.datadoghq.trace.Service;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
+import sun.reflect.generics.reflectiveObjects.NotImplementedException;
/** List writer used by tests mostly */
public class ListWriter extends CopyOnWriteArrayList<List<DDBaseSpan<?>>> implements Writer {
@@ -20,6 +22,11 @@ public class ListWriter extends CopyOnWriteArrayList<List<DDBaseSpan<?>>> implem
add(trace);
}
+ @Override
+ public void writeServices(final List<Service> services) {
+ throw new NotImplementedException();
+ }
+
@Override
public void start() {
clear();

MODIFY
dd-trace/src/main/java/com/datadoghq/trace/writer/LoggingWriter.java
dd-trace/src/main/java/com/datadoghq/trace/writer/LoggingWriter.java
package com.datadoghq.trace.writer;
import com.datadoghq.trace.DDBaseSpan;
+import com.datadoghq.trace.Service;
import com.google.auto.service.AutoService;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
@@ -14,6 +15,11 @@ public class LoggingWriter implements Writer {
log.info("write(trace): {}", trace);
}
+ @Override
+ public void writeServices(final List<Service> services) {
+ log.info("additional service information: {}", services);
+ }
+
@Override
public void close() {
log.info("close()");

MODIFY
dd-trace/src/main/java/com/datadoghq/trace/writer/Writer.java
dd-trace/src/main/java/com/datadoghq/trace/writer/Writer.java
package com.datadoghq.trace.writer;
import com.datadoghq.trace.DDBaseSpan;
+import com.datadoghq.trace.Service;
import java.util.List;
/** A writer is responsible to send collected spans to some place */
@@ -13,6 +14,13 @@ public interface Writer {
*/
void write(List<DDBaseSpan<?>> trace);
+ /**
+ * Report additional service information to the endpoint
+ *
+ * @param services a list of extra information about services
+ */
+ void writeServices(List<Service> services);
+
/** Start the writer */
void start();

ADD
dd-trace/src/test/groovy/com/datadoghq/trace/ServiceTest.groovy
+package com.datadoghq.trace
+
+import com.datadoghq.trace.sampling.AllSampler
+import com.datadoghq.trace.writer.DDAgentWriter
+import org.mockito.Mockito
+import spock.lang.Specification
+
+class ServiceTest extends Specification {
+
+
+ def "getter/setter"() {
+
+ setup:
+ def service = new Service("service-name", "app-name", Service.AppType.CUSTOM)
+
+ expect:
+ service.getName() == "service-name"
+ service.getAppName() == "app-name"
+ service.getAppType() == Service.AppType.CUSTOM
+
+ }
+
+ def "enum"() {
+
+ expect:
+ Service.AppType.values().size() == 3
+ Service.AppType.DB.toString() == "db"
+ Service.AppType.WEB.toString() == "web"
+ Service.AppType.CUSTOM.toString() == "custom"
+
+ }
+
+ def "add extra info about a specific service"() {
+
+ setup:
+ def tracer = new DDTracer()
+ def service = new Service("service-name", "app-name", Service.AppType.CUSTOM)
+
+ when:
+ tracer.addServiceInfo(service)
+
+ then:
+ tracer.getServiceInfo().size() == 1
+ tracer.getServiceInfo().get(0) == service
+
+ }
+
+ def "add a extra info is reported to the writer"() {
+
+ setup:
+ def writer = Mockito.spy(new DDAgentWriter())
+ def tracer = new DDTracer(writer, new AllSampler())
+
+
+ when:
+ tracer.addServiceInfo(new Service("service-name", "app-name", Service.AppType.CUSTOM))
+
+ then:
+ Mockito.verify(writer, Mockito.times(1)).writeServices(Mockito.any(List.class))
+
+ }
+
+}

Ability to add extra service information (WIP)