Added dd-trace.yaml config file resolution in resolver + default service name in tracer
This commit is contained in:
parent
fa98552f82
commit
832d8918c0
7
pom.xml
7
pom.xml
|
@ -18,6 +18,11 @@
|
|||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.8.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-yaml</artifactId>
|
||||
<version>2.8.8</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Logging dependencies -->
|
||||
<dependency>
|
||||
|
@ -40,7 +45,7 @@
|
|||
<dependency>
|
||||
<groupId>io.opentracing.contrib</groupId>
|
||||
<artifactId>opentracing-tracerresolver</artifactId>
|
||||
<version>0.0.3</version>
|
||||
<version>0.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
|
|
@ -14,7 +14,7 @@ import com.datadoghq.trace.propagation.Codec;
|
|||
import com.datadoghq.trace.propagation.HTTPCodec;
|
||||
import com.datadoghq.trace.sampling.AllSampler;
|
||||
import com.datadoghq.trace.sampling.Sampler;
|
||||
import com.datadoghq.trace.writer.LoggingWritter;
|
||||
import com.datadoghq.trace.writer.DDAgentWriter;
|
||||
import com.datadoghq.trace.writer.Writer;
|
||||
|
||||
import io.opentracing.Span;
|
||||
|
@ -36,6 +36,11 @@ public class DDTracer implements io.opentracing.Tracer {
|
|||
*/
|
||||
private final Sampler sampler;
|
||||
|
||||
/**
|
||||
* Default service name if none provided on the trace or span
|
||||
*/
|
||||
private final String defaultServiceName;
|
||||
|
||||
/**
|
||||
* Span context decorators
|
||||
*/
|
||||
|
@ -45,15 +50,29 @@ public class DDTracer implements io.opentracing.Tracer {
|
|||
private final static Logger logger = LoggerFactory.getLogger(DDTracer.class);
|
||||
private final CodecRegistry registry;
|
||||
|
||||
public static final String UNASSIGNED_DEFAULT_SERVICE_NAME = "unnamed-java-app";
|
||||
public static final Writer UNASSIGNED_WRITER = new DDAgentWriter();
|
||||
public static final Sampler UNASSIGNED_SAMPLER = new AllSampler();
|
||||
|
||||
/**
|
||||
* Default constructor, trace/spans are logged, no trace/span dropped
|
||||
*/
|
||||
public DDTracer() {
|
||||
this(new LoggingWritter(), new AllSampler());
|
||||
this(UNASSIGNED_WRITER);
|
||||
}
|
||||
|
||||
public DDTracer(Writer writer) {
|
||||
this(writer, new AllSampler());
|
||||
}
|
||||
|
||||
public DDTracer(Writer writer, Sampler sampler) {
|
||||
this(UNASSIGNED_DEFAULT_SERVICE_NAME,writer,sampler);
|
||||
}
|
||||
|
||||
public DDTracer(String defaultServiceName,Writer writer, Sampler sampler) {
|
||||
this.defaultServiceName = defaultServiceName;
|
||||
this.writer = writer;
|
||||
this.writer.start();
|
||||
this.sampler = sampler;
|
||||
registry = new CodecRegistry();
|
||||
registry.register(Format.Builtin.HTTP_HEADERS, new HTTPCodec());
|
||||
|
@ -261,8 +280,12 @@ public class DDTracer implements io.opentracing.Tracer {
|
|||
}
|
||||
|
||||
String serviceName = this.serviceName;
|
||||
if (serviceName == null && this.parent != null) {
|
||||
if (serviceName == null) {
|
||||
if(p != null){
|
||||
serviceName = p.getServiceName();
|
||||
}else{
|
||||
serviceName = defaultServiceName;
|
||||
}
|
||||
}
|
||||
|
||||
//this.operationName, this.tags,
|
||||
|
|
|
@ -40,4 +40,12 @@ public class DBServiceDecorator implements DDSpanContextDecorator {
|
|||
context.setResourceName(String.valueOf(value));
|
||||
}
|
||||
}
|
||||
|
||||
public String getComponentName() {
|
||||
return componentName;
|
||||
}
|
||||
|
||||
public String getDesiredServiceName() {
|
||||
return desiredServiceName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,4 +48,12 @@ public class HTTPServiceDecorator implements DDSpanContextDecorator {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getComponentName() {
|
||||
return componentName;
|
||||
}
|
||||
|
||||
public String getDesiredServiceName() {
|
||||
return desiredServiceName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,30 @@
|
|||
package com.datadoghq.trace.resolver;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.datadoghq.trace.DDTracer;
|
||||
import com.datadoghq.trace.integration.DBServiceDecorator;
|
||||
import com.datadoghq.trace.integration.DDSpanContextDecorator;
|
||||
import com.datadoghq.trace.integration.HTTPServiceDecorator;
|
||||
import com.datadoghq.trace.sampling.AllSampler;
|
||||
import com.datadoghq.trace.sampling.RateSampler;
|
||||
import com.datadoghq.trace.sampling.Sampler;
|
||||
import com.datadoghq.trace.writer.DDAgentWriter;
|
||||
import com.datadoghq.trace.writer.DDApi;
|
||||
import com.datadoghq.trace.writer.LoggingWritter;
|
||||
import com.datadoghq.trace.writer.Writer;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||
import com.google.auto.service.AutoService;
|
||||
|
||||
import io.opentracing.Tracer;
|
||||
import io.opentracing.contrib.tracerresolver.TracerResolver;
|
||||
|
||||
|
@ -11,9 +32,97 @@ import io.opentracing.contrib.tracerresolver.TracerResolver;
|
|||
@AutoService(TracerResolver.class)
|
||||
public class DDTracerResolver extends TracerResolver{
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(DDTracerResolver.class);
|
||||
|
||||
// private static final ServiceLoader<Writer> WRITERS = ServiceLoader.load(Writer.class);
|
||||
// private static final ServiceLoader<Sampler> SAMPLERS = ServiceLoader.load(Sampler.class);
|
||||
// private static final ServiceLoader<DDSpanContextDecorator> DECORATORS = ServiceLoader.load(DDSpanContextDecorator.class);
|
||||
|
||||
public static final String TRACER_CONFIG = "dd-trace.yaml";
|
||||
private final ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
|
||||
|
||||
@Override
|
||||
protected Tracer resolve() {
|
||||
// TODO find a way to close the reader ...
|
||||
return new DDTracer(new DDAgentWriter(), new AllSampler());
|
||||
logger.info("Creating the Datadog tracer");
|
||||
|
||||
//Find a resource file named dd-trace.yml
|
||||
DDTracer tracer = null;
|
||||
try {
|
||||
Enumeration<URL> iter = Thread.currentThread().getContextClassLoader().getResources(TRACER_CONFIG);
|
||||
while (iter.hasMoreElements()) {
|
||||
|
||||
TracerConfig config = objectMapper.readValue(new File(iter.nextElement().getFile()),TracerConfig.class);
|
||||
|
||||
String defaultServiceName = config.getDefaultServiceName()!=null?config.getDefaultServiceName():DDTracer.UNASSIGNED_DEFAULT_SERVICE_NAME;
|
||||
|
||||
//Create writer
|
||||
Writer writer = DDTracer.UNASSIGNED_WRITER;
|
||||
if(config.getWriter()!=null &&config.getWriter().get("type")!=null){
|
||||
String type = (String) config.getWriter().get("type");
|
||||
if(type.equals(DDAgentWriter.class.getSimpleName())){
|
||||
String host = config.getWriter().get("host")!=null?(String)config.getWriter().get("host"):DDAgentWriter.DEFAULT_HOSTNAME;
|
||||
Integer port = config.getWriter().get("port")!=null?(Integer)config.getWriter().get("port"):DDAgentWriter.DEFAULT_PORT;
|
||||
DDApi api = new DDApi(host, port);
|
||||
writer = new DDAgentWriter(api);
|
||||
}else if(type.equals(LoggingWritter.class.getSimpleName())){
|
||||
writer = new LoggingWritter();
|
||||
}
|
||||
}
|
||||
|
||||
//Create sampler
|
||||
Sampler rateSampler = DDTracer.UNASSIGNED_SAMPLER;
|
||||
if(config.getSampler()!=null && config.getSampler().get("type")!=null){
|
||||
String type = (String) config.getSampler().get("type");
|
||||
if(type.equals(AllSampler.class.getSimpleName())){
|
||||
rateSampler = new AllSampler();
|
||||
}else if(type.equals(RateSampler.class.getSimpleName())){
|
||||
rateSampler = new RateSampler((Double)config.getSampler().get("rate"));
|
||||
}
|
||||
}
|
||||
|
||||
//Create tracer
|
||||
tracer = new DDTracer(defaultServiceName,writer,rateSampler);
|
||||
|
||||
//Find decorators
|
||||
if(config.getDecorators()!=null){
|
||||
for(Map<String,Object> map : config.getDecorators()){
|
||||
if(map.get("type")!=null){
|
||||
DDSpanContextDecorator decorator = null;
|
||||
String componentName = (String) map.get("componentName");
|
||||
String desiredServiceName = map.get("desiredServiceName")!=null?(String) map.get("desiredServiceName"):(String) map.get("componentName");
|
||||
|
||||
if(map.get("type").equals(HTTPServiceDecorator.class.getSimpleName())){
|
||||
decorator = new HTTPServiceDecorator(componentName,desiredServiceName);
|
||||
tracer.addDecorator(decorator);
|
||||
}else if(map.get("type").equals(DBServiceDecorator.class.getSimpleName())){
|
||||
decorator = new DBServiceDecorator(componentName,desiredServiceName);
|
||||
tracer.addDecorator(decorator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("Could not load tracer configuration file. Loading default tracer.",e);
|
||||
}
|
||||
|
||||
if(tracer==null){
|
||||
logger.info("No valid configuration file 'dd-trace.yaml' found. Loading default tracer.");
|
||||
tracer = new DDTracer();
|
||||
}
|
||||
|
||||
return tracer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void main(String[] args){
|
||||
ServiceLoader<TracerResolver> RESOLVERS = ServiceLoader.load(TracerResolver.class);
|
||||
|
||||
for (TracerResolver value : RESOLVERS){
|
||||
value.resolveTracer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package com.datadoghq.trace.resolver;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Tracer configuration
|
||||
*/
|
||||
public class TracerConfig {
|
||||
private String defaultServiceName;
|
||||
private Map<String,Object> writer;
|
||||
private Map<String,Object> sampler;
|
||||
private List<Map<String,Object>> decorators;
|
||||
|
||||
public String getDefaultServiceName() {
|
||||
return defaultServiceName;
|
||||
}
|
||||
public void setDefaultServiceName(String defaultServiceName) {
|
||||
this.defaultServiceName = defaultServiceName;
|
||||
}
|
||||
public Map<String, Object> getWriter() {
|
||||
return writer;
|
||||
}
|
||||
public void setWriter(Map<String, Object> writer) {
|
||||
this.writer = writer;
|
||||
}
|
||||
public Map<String, Object> getSampler() {
|
||||
return sampler;
|
||||
}
|
||||
public void setSampler(Map<String, Object> sampler) {
|
||||
this.sampler = sampler;
|
||||
}
|
||||
public List<Map<String, Object>> getDecorators() {
|
||||
return decorators;
|
||||
}
|
||||
public void setDecorators(List<Map<String, Object>> decorators) {
|
||||
this.decorators = decorators;
|
||||
}
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
package com.datadoghq.trace.sampling;
|
||||
|
||||
|
||||
import io.opentracing.Span;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
|
||||
import io.opentracing.Span;
|
||||
|
||||
|
||||
/**
|
||||
* This sampler sample the traces at a predefined rate.
|
||||
|
@ -12,6 +15,7 @@ import org.slf4j.LoggerFactory;
|
|||
* Keep (100 * `sample_rate`)% of the traces.
|
||||
* It samples randomly, its main purpose is to reduce the instrumentation footprint.
|
||||
*/
|
||||
@AutoService(Sampler.class)
|
||||
public class RateSampler implements Sampler {
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ 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.*;
|
||||
|
@ -14,6 +16,7 @@ import java.util.concurrent.*;
|
|||
* It handles writes asynchronuously so the calling threads are automatically released. However, if too much spans are collected
|
||||
* the writers can reach a state where it is forced to drop incoming spans.
|
||||
*/
|
||||
@AutoService(Writer.class)
|
||||
public class DDAgentWriter implements Writer {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DDAgentWriter.class.getName());
|
||||
|
@ -21,8 +24,8 @@ public class DDAgentWriter implements Writer {
|
|||
/**
|
||||
* Default location of the DD agent
|
||||
*/
|
||||
private static final String DEFAULT_HOSTNAME = "localhost";
|
||||
private static final int DEFAULT_PORT = 8126;
|
||||
public static final String DEFAULT_HOSTNAME = "localhost";
|
||||
public static final int DEFAULT_PORT = 8126;
|
||||
|
||||
/**
|
||||
* Maximum number of spans kept in memory
|
||||
|
@ -64,9 +67,6 @@ public class DDAgentWriter implements Writer {
|
|||
|
||||
tokens = new Semaphore(DEFAULT_MAX_SPANS);
|
||||
traces = new ArrayBlockingQueue<List<Span>>(DEFAULT_MAX_SPANS);
|
||||
|
||||
executor.submit(new SpansSendingTask());
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -83,6 +83,14 @@ public class DDAgentWriter implements Writer {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.datadoghq.trace.writer.Writer#start()
|
||||
*/
|
||||
@Override
|
||||
public void start() {
|
||||
executor.submit(new SpansSendingTask());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.datadoghq.trace.Writer#close()
|
||||
*/
|
||||
|
|
|
@ -5,8 +5,11 @@ import java.util.List;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
|
||||
import io.opentracing.Span;
|
||||
|
||||
@AutoService(Writer.class)
|
||||
public class LoggingWritter implements Writer{
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(LoggingWritter.class.getName());
|
||||
|
@ -20,4 +23,9 @@ public class LoggingWritter implements Writer{
|
|||
public void close() {
|
||||
logger.info("close()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
logger.info("start()");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,11 @@ public interface Writer {
|
|||
*/
|
||||
void write(List<Span> trace);
|
||||
|
||||
/**
|
||||
* Start the writer
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Indicates to the writer that no future writing will come and it should terminates all connections and tasks
|
||||
*/
|
||||
|
|
|
@ -59,9 +59,10 @@ public class DDSpanTest {
|
|||
|
||||
final String expectedName = "operationName";
|
||||
|
||||
DDSpan span = new DDTracer().buildSpan(expectedName).withServiceName("foo").start();
|
||||
DDSpan span = new DDTracer().buildSpan(expectedName).start();
|
||||
// ResourceName = expectedName
|
||||
assertThat(span.getResourceName()).isEqualTo(expectedName);
|
||||
assertThat(span.getServiceName()).isEqualTo(DDTracer.UNASSIGNED_DEFAULT_SERVICE_NAME);
|
||||
|
||||
// ResourceName = expectedResourceName
|
||||
final String expectedResourceName = "fake";
|
||||
|
@ -71,6 +72,7 @@ public class DDSpanTest {
|
|||
.withServiceName("foo").start();
|
||||
|
||||
assertThat(span.getResourceName()).isEqualTo(expectedResourceName);
|
||||
assertThat(span.getServiceName()).isEqualTo("foo");
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package com.datadoghq.trace.resolver;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.datadoghq.trace.DDTracer;
|
||||
import com.datadoghq.trace.integration.DDSpanContextDecorator;
|
||||
import com.datadoghq.trace.integration.HTTPServiceDecorator;
|
||||
|
||||
public class TracerResolverTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
DDTracerResolver tracerResolver = new DDTracerResolver();
|
||||
DDTracer tracer = (DDTracer) tracerResolver.resolve();
|
||||
|
||||
List<DDSpanContextDecorator> decorators = tracer.getSpanContextDecorators();
|
||||
|
||||
assertThat(decorators.size()).isEqualTo(1);
|
||||
DDSpanContextDecorator decorator = decorators.get(0);
|
||||
assertThat(decorator.getClass()).isEqualTo(HTTPServiceDecorator.class);
|
||||
HTTPServiceDecorator httpServiceDecorator = (HTTPServiceDecorator) decorator;
|
||||
assertThat(httpServiceDecorator.getComponentName()).isEqualTo("hello");
|
||||
assertThat(httpServiceDecorator.getDesiredServiceName()).isEqualTo("world");
|
||||
}
|
||||
|
||||
}
|
|
@ -47,6 +47,7 @@ public class DDAgentWriterTest {
|
|||
mockedAPI = mock(DDApi.class);
|
||||
when(mockedAPI.sendTraces(traces)).thenReturn(true);
|
||||
ddAgentWriter = new DDAgentWriter(mockedAPI);
|
||||
ddAgentWriter.start();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
defaultServiceName: java-app
|
||||
writer:
|
||||
type: DDAgentWriter
|
||||
host: localhost
|
||||
port: 10000
|
||||
sampler:
|
||||
type: AllSampler
|
||||
decorators:
|
||||
- type: HTTPServiceDecorator
|
||||
componentName: hello
|
||||
desiredServiceName: world
|
||||
|
||||
|
Loading…
Reference in New Issue