Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Guillaume Polaert 2017-05-29 16:10:26 +02:00
commit 2952299401
17 changed files with 399 additions and 274 deletions

View File

@ -1,17 +1,18 @@
# Decorators are used to add extra information to span
# Could be DBServiceDecorator, MapperDecorator or HTTPServiceDecorator
decorators:
- type: HTTP
componentName: java-web-servlet
- type: HTTP
componentName: java-okhttp
desiredServiceName: http-client
- type: DB
componentName: java-mongo
desiredServiceName: mongo
- type: DB
componentName: java-jdbc
desiredServiceName: jdbc
- type: HTTP
componentName: java-aws-sdk
desiredServiceName: aws-client
- type: HTTPComponent
matchingValue: java-web-servlet
- type: HTTPComponent
matchingValue: java-okhttp
setValue: http-client
- type: DBComponent
matchingValue: java-mongo
setValue: mongo
- type: DBComponent
matchingValue: java-jdbc
setValue: jdbc
- type: HTTPComponent
matchingValue: java-aws-sdk
setValue: aws-client
- type: URLAsResourceName

View File

@ -1,53 +0,0 @@
package com.datadoghq.trace.integration;
import com.datadoghq.trace.DDSpanContext;
import io.opentracing.tag.Tags;
/**
* This span decorator leverages DB tags. It allows the dev to define a custom
* service name and retrieves some DB meta such as the statement
*/
public class DB implements DDSpanContextDecorator {
protected final String componentName;
protected final String desiredServiceName;
public DB(String componentName) {
super();
this.componentName = componentName;
this.desiredServiceName = null;
}
public DB(String componentName,String desiredServiceName) {
super();
this.componentName = componentName;
this.desiredServiceName = desiredServiceName;
}
@Override
public void afterSetTag(DDSpanContext context, String tag, Object value) {
//Assign service name
if(tag.equals(Tags.COMPONENT.getKey()) && value.equals(componentName)){
if(desiredServiceName != null){
context.setServiceName(desiredServiceName);
}
//Assign span type to DB
context.setSpanType("db");
}
//Assign resource name
if(tag.equals(Tags.DB_STATEMENT.getKey())){
context.setResourceName(String.valueOf(value));
}
}
public String getComponentName() {
return componentName;
}
public String getDesiredServiceName() {
return desiredServiceName;
}
}

View File

@ -0,0 +1,35 @@
package com.datadoghq.trace.integration;
import com.datadoghq.trace.DDSpanContext;
import com.datadoghq.trace.DDTags;
import io.opentracing.tag.Tags;
/**
* This span decorator leverages DB tags. It allows the dev to define a custom
* service name and retrieves some DB meta such as the statement
*/
public class DBComponent extends DDSpanContextDecorator {
public DBComponent() {
super();
this.setMatchingTag(Tags.COMPONENT.getKey());
this.setSetTag(DDTags.SERVICE_NAME);
}
@Override
public boolean afterSetTag(DDSpanContext context, String tag, Object value) {
//Assign service name
if(super.afterSetTag(context, tag, value)){
//Assign span type to DB
context.setSpanType("db");
//Assign resource name
if(tag.equals(Tags.DB_STATEMENT.getKey())){
context.setResourceName(String.valueOf(value));
}
return true;
}
return false;
}
}

View File

@ -5,16 +5,56 @@ import com.datadoghq.trace.DDSpanContext;
/**
* Span decorators are called when new tags are written and proceed to various remappings and enrichments
*/
public interface DDSpanContextDecorator {
public abstract class 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);
private String matchingTag;
private String matchingValue;
private String setTag;
private String setValue;
public boolean afterSetTag(DDSpanContext context, String tag, Object value){
if(tag.equals(this.getMatchingTag()) && (this.getMatchingValue()==null || value.equals(this.getMatchingValue()))){
String targetTag = getSetTag()==null?tag:getSetTag();
String targetValue = getSetValue()==null?String.valueOf(value):getSetTag();
context.setTag(targetTag, targetValue);
return true;
}else{
return false;
}
}
public String getMatchingTag() {
return matchingTag;
}
public void setMatchingTag(String tag) {
this.matchingTag = tag;
}
public String getMatchingValue() {
return matchingValue;
}
public void setMatchingValue(String value) {
this.matchingValue = value;
}
public String getSetTag() {
return setTag;
}
public void setSetTag(String targetTag) {
this.setTag = targetTag;
}
public String getSetValue() {
return setValue;
}
public void setSetValue(String targetValue) {
this.setValue = targetValue;
}
}

View File

@ -1,62 +0,0 @@
package com.datadoghq.trace.integration;
import java.net.MalformedURLException;
import java.net.URL;
import com.datadoghq.trace.DDSpanContext;
import io.opentracing.tag.Tags;
/**
* This span decorator leverages HTTP tags. It allows the dev to define a custom
* service name and retrieves some HTTP meta such as the request path
*/
public class HTTP implements DDSpanContextDecorator {
protected final String componentName;
protected final String desiredServiceName;
public HTTP(String componentName) {
super();
this.componentName = componentName;
this.desiredServiceName = null;
}
public HTTP(String componentName,String desiredServiceName) {
super();
this.componentName = componentName;
this.desiredServiceName = desiredServiceName;
}
@Override
public void afterSetTag(DDSpanContext context, String tag, Object value) {
//Assign service name
if(tag.equals(Tags.COMPONENT.getKey()) && value.equals(componentName)){
if(desiredServiceName != null){
context.setServiceName(desiredServiceName);
}
//Assign span type to WEB
context.setSpanType("web");
}
//Assign resource name
if(tag.equals(Tags.HTTP_URL.getKey())){
try {
String path = new URL(String.valueOf(value)).getPath();
context.setResourceName(path);
} catch (MalformedURLException e) {
context.setResourceName(String.valueOf(value));
}
}
}
public String getComponentName() {
return componentName;
}
public String getDesiredServiceName() {
return desiredServiceName;
}
}

View File

@ -0,0 +1,32 @@
package com.datadoghq.trace.integration;
import com.datadoghq.trace.DDSpanContext;
import com.datadoghq.trace.DDTags;
import io.opentracing.tag.Tags;
/**
* This span decorator leverages HTTP tags. It allows the dev to define a custom
* service name and retrieves some HTTP meta such as the request path
*/
public class HTTPComponent extends DDSpanContextDecorator {
public HTTPComponent() {
super();
this.setMatchingTag(Tags.COMPONENT.getKey());
this.setSetTag(DDTags.SERVICE_NAME);
}
@Override
public boolean afterSetTag(DDSpanContext context, String tag, Object value) {
//Assign service name
if(super.afterSetTag(context, tag, value)){
//Assign span type to WEB
context.setSpanType("web");
return true;
}else{
return false;
}
}
}

View File

@ -1,37 +0,0 @@
package com.datadoghq.trace.integration;
import java.util.Map;
import com.datadoghq.trace.DDSpanContext;
import com.datadoghq.trace.DDTags;
/**
* This is a generic decorator, it remaps some tags to other tags
*/
public class MapperDecorator implements DDSpanContextDecorator {
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(DDTags.SPAN_TYPE)){
context.setSpanType(String.valueOf(value));
}else if(toAssign.equals(DDTags.SERVICE_NAME)){
context.setServiceName(String.valueOf(value));
}else if(toAssign.equals(DDTags.RESOURCE_NAME)){
context.setResourceName(String.valueOf(value));
}else{
//General remap
context.setTag(toAssign, value);
}
}
}
}

View File

@ -0,0 +1,34 @@
package com.datadoghq.trace.integration;
import java.net.MalformedURLException;
import com.datadoghq.trace.DDSpanContext;
import com.datadoghq.trace.DDTags;
import io.opentracing.tag.Tags;
public class URLAsResourceName extends DDSpanContextDecorator {
public URLAsResourceName() {
super();
this.setMatchingTag(Tags.HTTP_URL.getKey());
this.setSetTag(DDTags.RESOURCE_NAME);
}
@Override
public boolean afterSetTag(DDSpanContext context, String tag, Object value) {
//Assign resource name
if(tag.equals(Tags.HTTP_URL.getKey())){
try {
String path = new java.net.URL(String.valueOf(value)).getPath();
context.setTag(this.getSetTag(),path);
} catch (MalformedURLException e) {
context.setResourceName(String.valueOf(value));
}
return true;
}else{
return false;
}
}
}

View File

@ -0,0 +1,69 @@
package com.datadoghq.trace.resolver;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datadoghq.trace.integration.DDSpanContextDecorator;
/**
* Create DDSpaDecorators from a valid configuration
*/
public class DDDecoratorsFactory {
private final static Logger logger = LoggerFactory.getLogger(DDDecoratorsFactory.class);
public static String DECORATORS_PACKAGE = "com.datadoghq.trace.integration.";
/**
* Create decorators from configuration
*
* @param decoratorsConfig
* @return the list of instanciated & configured decorators
*/
public static List<DDSpanContextDecorator> create(List<DDSpanDecoratorConfig> decoratorsConfig){
List<DDSpanContextDecorator> decorators = new ArrayList<DDSpanContextDecorator>();
for (DDSpanDecoratorConfig decoratorConfig : decoratorsConfig) {
if(decoratorConfig.getType()==null){
logger.warn("Cannot create decorator without type from configuration {}",decoratorConfig);
continue;
}
//Find class and create
Class<?> decoratorClass;
try {
decoratorClass = Class.forName(DECORATORS_PACKAGE+decoratorConfig.getType());
} catch (ClassNotFoundException e) {
logger.warn("Cannot create decorator as the class {} is not defined. Provided configuration {}",decoratorConfig);
continue;
}
DDSpanContextDecorator decorator = null;
try{
decorator = (DDSpanContextDecorator) decoratorClass.getConstructor().newInstance();
}catch(Exception e){
logger.warn("Cannot create decorator as we could not invoke the default constructor. Provided configuration {}",decoratorConfig);
continue;
}
//Fill with config values
if(decoratorConfig.getMatchingTag()!=null){
decorator.setMatchingTag(decoratorConfig.getMatchingTag());
}
if(decoratorConfig.getMatchingValue()!=null){
decorator.setMatchingValue(decoratorConfig.getMatchingValue());
}
if(decoratorConfig.getSetTag()!=null){
decorator.setSetTag(decoratorConfig.getSetTag());
}
if(decoratorConfig.getSetValue()!=null){
decorator.setSetValue(decoratorConfig.getSetValue());
}
decorators.add(decorator);
}
return decorators;
}
}

View File

@ -0,0 +1,71 @@
package com.datadoghq.trace.resolver;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
/**
*
*/
public class DDSpanDecoratorConfig {
private String type;
private String matchingTag;
private String matchingValue;
private String setTag;
private String setValue;
public String getMatchingTag() {
return matchingTag;
}
public void setMatchingTag(String matchingTag) {
this.matchingTag = matchingTag;
}
public String getMatchingValue() {
return matchingValue;
}
public void setMatchingValue(String matchingValue) {
this.matchingValue = matchingValue;
}
public String getSetTag() {
return setTag;
}
public void setSetTag(String setTag) {
this.setTag = setTag;
}
public String getSetValue() {
return setValue;
}
public void setSetValue(String setValue) {
this.setValue = setValue;
}
public void setType(String type) {
this.type = type;
}
public String getType() {
return type;
}
@Override
public String toString() {
try {
return new ObjectMapper(new YAMLFactory()).writeValueAsString(this);
} catch (JsonProcessingException e) {
return null;
}
}
}

View File

@ -0,0 +1,55 @@
package com.datadoghq.trace.resolver;
import com.datadoghq.trace.DDTracer;
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;
/**
* Create a tracer from a configuration file
*/
public class DDTracerFactory {
/**
* Create a tracer from a TracerConfig object
*
* @param config
* @return the corresponding tracer
*/
public static DDTracer create(TracerConfig config){
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
return new DDTracer(defaultServiceName, writer, rateSampler);
}
}

View File

@ -3,23 +3,13 @@ package com.datadoghq.trace.resolver;
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.DB;
import com.datadoghq.trace.integration.DDSpanContextDecorator;
import com.datadoghq.trace.integration.HTTP;
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;
@ -52,35 +42,7 @@ public class DDTracerResolver extends TracerResolver {
while (iter.hasMoreElements()) {
TracerConfig config = objectMapper.readValue(iter.nextElement().openStream(), 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);
tracer = DDTracerFactory.create(config);
break; // ONLY the closest resource file is taken into account
}
@ -90,20 +52,8 @@ public class DDTracerResolver extends TracerResolver {
TracerConfig config = objectMapper.readValue(iter.nextElement().openStream(), TracerConfig.class);
//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 = (String) map.get("desiredServiceName");
if (map.get("type").equals(HTTP.class.getSimpleName())) {
decorator = new HTTP(componentName, desiredServiceName);
tracer.addDecorator(decorator);
} else if (map.get("type").equals(DB.class.getSimpleName())) {
decorator = new DB(componentName, desiredServiceName);
tracer.addDecorator(decorator);
}
}
for(DDSpanContextDecorator decorator:DDDecoratorsFactory.create(config.getDecorators())){
tracer.addDecorator(decorator);
}
}

View File

@ -3,6 +3,10 @@ package com.datadoghq.trace.resolver;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
/**
* Tracer configuration
*/
@ -10,7 +14,7 @@ public class TracerConfig {
private String defaultServiceName;
private Map<String,Object> writer;
private Map<String,Object> sampler;
private List<Map<String,Object>> decorators;
private List<DDSpanDecoratorConfig> decorators;
public String getDefaultServiceName() {
return defaultServiceName;
@ -30,10 +34,20 @@ public class TracerConfig {
public void setSampler(Map<String, Object> sampler) {
this.sampler = sampler;
}
public List<Map<String, Object>> getDecorators() {
public List<DDSpanDecoratorConfig> getDecorators() {
return decorators;
}
public void setDecorators(List<Map<String, Object>> decorators) {
public void setDecorators(List<DDSpanDecoratorConfig> decorators) {
this.decorators = decorators;
}
@Override
public String toString() {
try {
return new ObjectMapper(new YAMLFactory()).writeValueAsString(this);
} catch (JsonProcessingException e) {
//FIXME better toString() while config object stabilized
return null;
}
}
}

View File

@ -1,11 +0,0 @@
# Decorators are used to add extra information to span
# Could be DBServiceDecorator, MapperDecorator or HTTPServiceDecorator
decorators:
# This span decorator leverages HTTP tags such as the URL requested
- type: HTTP
componentName: http
desiredServiceName: unnamed-java-http
# This span decorator leverages DB tags such as the statement requested
- type: DB
componentName: db
desiredServiceName: unnamed-java-db

View File

@ -1,21 +0,0 @@
# Service name used if none is provided in the app
defaultServiceName: unnamed-java-app
# The writer to use.
# Could be: LoggingWritter or DDAgentWriter (default)
writer:
# LoggingWriter: Spans are logged using the application configuration
# DDAgentWriter: Spans are forwarding to a Datadog Agent
# - Param 'host': the hostname where the DD Agent running (default: localhost)
# - Param 'port': the port to reach the DD Agent (default: 8126)
type: DDAgentWriter
host: localhost
port: 8126
# The sampler to use.
# Could be: AllSampler (default) or RateSampler
sampler:
# AllSampler: all spans are reported to the writer
# RateSample: only a portion of spans are reported to the writer
# - Param 'rate': the portion of spans to keep
type: AllSampler

View File

@ -8,7 +8,8 @@ import org.junit.Test;
import com.datadoghq.trace.DDTracer;
import com.datadoghq.trace.integration.DDSpanContextDecorator;
import com.datadoghq.trace.integration.HTTP;
import com.datadoghq.trace.integration.HTTPComponent;
import com.datadoghq.trace.integration.URLAsResourceName;
public class TracerResolverTest {
@ -19,12 +20,18 @@ public class TracerResolverTest {
List<DDSpanContextDecorator> decorators = tracer.getSpanContextDecorators();
assertThat(decorators.size()).isEqualTo(1);
assertThat(decorators.size()).isEqualTo(2);
DDSpanContextDecorator decorator = decorators.get(0);
assertThat(decorator.getClass()).isEqualTo(HTTP.class);
HTTP httpServiceDecorator = (HTTP) decorator;
assertThat(httpServiceDecorator.getComponentName()).isEqualTo("hello");
assertThat(httpServiceDecorator.getDesiredServiceName()).isEqualTo("world");
assertThat(decorator.getClass()).isEqualTo(HTTPComponent.class);
HTTPComponent httpServiceDecorator = (HTTPComponent) decorator;
assertThat(httpServiceDecorator.getMatchingTag()).isEqualTo("component");
assertThat(httpServiceDecorator.getMatchingValue()).isEqualTo("hello");
assertThat(httpServiceDecorator.getSetValue()).isEqualTo("world");
decorator = decorators.get(1);
assertThat(decorator.getClass()).isEqualTo(URLAsResourceName.class);
}
}

View File

@ -1,4 +1,5 @@
decorators:
- type: HTTP
componentName: hello
desiredServiceName: world
- type: HTTPComponent
matchingValue: hello
setValue: world
- type: URLAsResourceName