From caa799ddc1519c22ba9b15b303df917c01bf1d25 Mon Sep 17 00:00:00 2001 From: Nikolay Martynov Date: Wed, 12 Sep 2018 13:35:54 -0400 Subject: [PATCH] Refactor DDTraceConfig to a Config we can use globally This would allow us to use same configuration ingrastructure in different modules. E.g. upcoming JMX. --- dd-trace-api/dd-trace-api.gradle | 9 + .../main/java/datadog/trace/api/Config.java | 162 ++++++++++++++++ .../datadog/trace/api/ConfigTest.groovy | 183 ++++++++++++++++++ .../java/datadog/opentracing/DDTracer.java | 62 +++--- .../decorators/DDDecoratorsFactory.java | 4 +- .../decorators/ServletContextDecorator.java | 6 +- .../resolver/DDTracerResolver.java | 31 +-- .../datadog/trace/common/DDTraceConfig.java | 73 ------- .../trace/common/sampling/Sampler.java | 13 +- .../datadog/trace/common/util/Config.java | 46 ----- .../trace/common/writer/DDAgentWriter.java | 10 +- .../datadog/trace/common/writer/Writer.java | 33 ++-- .../opentracing/DDSpanBuilderTest.groovy | 3 +- .../datadog/opentracing/DDSpanTest.groovy | 6 +- .../decorators/SpanDecoratorTest.groovy | 46 ++--- .../resolver/DDTracerResolverTest.groovy | 34 ++++ .../resolver/TracerResolverTest.groovy | 65 ------- .../datadog/trace/DDTraceConfigTest.groovy | 182 ----------------- .../groovy/datadog/trace/DDTracerTest.groovy | 97 ++++++++++ .../groovy/DDApiIntegrationTest.groovy | 6 +- 20 files changed, 591 insertions(+), 480 deletions(-) create mode 100644 dd-trace-api/src/main/java/datadog/trace/api/Config.java create mode 100644 dd-trace-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy delete mode 100644 dd-trace-ot/src/main/java/datadog/trace/common/DDTraceConfig.java delete mode 100644 dd-trace-ot/src/main/java/datadog/trace/common/util/Config.java create mode 100644 dd-trace-ot/src/test/groovy/datadog/opentracing/resolver/DDTracerResolverTest.groovy delete mode 100644 dd-trace-ot/src/test/groovy/datadog/opentracing/resolver/TracerResolverTest.groovy delete mode 100644 dd-trace-ot/src/test/groovy/datadog/trace/DDTraceConfigTest.groovy create mode 100644 dd-trace-ot/src/test/groovy/datadog/trace/DDTracerTest.groovy diff --git a/dd-trace-api/dd-trace-api.gradle b/dd-trace-api/dd-trace-api.gradle index 1b9a00d340..8feb58f4a5 100644 --- a/dd-trace-api/dd-trace-api.gradle +++ b/dd-trace-api/dd-trace-api.gradle @@ -1,6 +1,15 @@ apply from: "${rootDir}/gradle/java.gradle" apply from: "${rootDir}/gradle/publish.gradle" +// These are tested outside of this module since this module mainly just defines 'API' +excludedClassesConverage += [ + 'datadog.trace.api.DDSpanTypes', + 'datadog.trace.api.DDTraceApiInfo', + 'datadog.trace.api.GlobalTracer*', + 'datadog.trace.api.CorrelationIdentifier', + 'datadog.trace.api.DDTags' +] + description = 'dd-trace-api' dependencies { compile deps.slf4j diff --git a/dd-trace-api/src/main/java/datadog/trace/api/Config.java b/dd-trace-api/src/main/java/datadog/trace/api/Config.java new file mode 100644 index 0000000000..5beab12c47 --- /dev/null +++ b/dd-trace-api/src/main/java/datadog/trace/api/Config.java @@ -0,0 +1,162 @@ +package datadog.trace.api; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import lombok.Getter; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; + +/** + * Config gives priority to system properties and falls back to environment variables. It also + * includes default values to ensure a valid config. + * + *

+ * + *

System properties are {@link Config#PREFIX}'ed. Environment variables are the same as the + * system property, but uppercased with '.' -> '_'. + */ +@Slf4j +@ToString(includeFieldNames = true) +public class Config { + /** Config keys below */ + private static final String PREFIX = "dd."; + + private static final Config INSTANCE = new Config(); + + public static final String SERVICE_NAME = "service.name"; + public static final String SERVICE_MAPPING = "service.mapping"; + public static final String WRITER_TYPE = "writer.type"; + public static final String AGENT_HOST = "agent.host"; + public static final String AGENT_PORT = "agent.port"; + public static final String PRIORITY_SAMPLING = "priority.sampling"; + public static final String TRACE_RESOLVER_ENABLED = "trace.resolver.enabled"; + public static final String SPAN_TAGS = "trace.span.tags"; + public static final String HEADER_TAGS = "trace.header.tags"; + + public static final String DEFAULT_SERVICE_NAME = "unnamed-java-app"; + + public static final String DD_AGENT_WRITER_TYPE = "DDAgentWriter"; + public static final String LOGGING_WRITER_TYPE = "LoggingWriter"; + public static final String DEFAULT_AGENT_WRITER_TYPE = DD_AGENT_WRITER_TYPE; + + public static final String DEFAULT_AGENT_HOST = "localhost"; + public static final int DEFAULT_AGENT_PORT = 8126; + + private static final String DEFAULT_PRIORITY_SAMPLING_ENABLED = "false"; + private static final String DEFAULT_TRACE_RESOLVER_ENABLED = "true"; + + @Getter private final String serviceName; + @Getter private final String writerType; + @Getter private final String agentHost; + @Getter private final int agentPort; + @Getter private final boolean prioritySamplingEnabled; + @Getter private final boolean traceResolverEnabled; + @Getter private final Map serviceMapping; + @Getter private final Map spanTags; + @Getter private final Map headerTags; + + // Read order: System Properties -> Env Variables, [-> default value] + // Visible for testing + Config() { + serviceName = getSettingFromEnvironment(SERVICE_NAME, DEFAULT_SERVICE_NAME); + writerType = getSettingFromEnvironment(WRITER_TYPE, DEFAULT_AGENT_WRITER_TYPE); + agentHost = getSettingFromEnvironment(AGENT_HOST, DEFAULT_AGENT_HOST); + agentPort = + Integer.valueOf( + getSettingFromEnvironment(AGENT_PORT, Integer.toString(DEFAULT_AGENT_PORT))); + prioritySamplingEnabled = + Boolean.valueOf( + getSettingFromEnvironment(PRIORITY_SAMPLING, DEFAULT_PRIORITY_SAMPLING_ENABLED)); + traceResolverEnabled = + Boolean.valueOf( + getSettingFromEnvironment(TRACE_RESOLVER_ENABLED, DEFAULT_TRACE_RESOLVER_ENABLED)); + serviceMapping = getMapSettingFromEnvironment(SERVICE_MAPPING, null); + spanTags = getMapSettingFromEnvironment(SPAN_TAGS, null); + headerTags = getMapSettingFromEnvironment(HEADER_TAGS, null); + } + + // Read order: Properties -> Parent + private Config(final Properties properties, final Config parent) { + serviceName = properties.getProperty(SERVICE_NAME, parent.serviceName); + writerType = properties.getProperty(WRITER_TYPE, parent.writerType); + agentHost = properties.getProperty(AGENT_HOST, parent.agentHost); + agentPort = + Integer.valueOf(properties.getProperty(AGENT_PORT, Integer.toString(parent.agentPort))); + prioritySamplingEnabled = + Boolean.valueOf( + properties.getProperty( + PRIORITY_SAMPLING, Boolean.toString(parent.prioritySamplingEnabled))); + traceResolverEnabled = + Boolean.valueOf( + properties.getProperty( + TRACE_RESOLVER_ENABLED, Boolean.toString(parent.traceResolverEnabled))); + serviceMapping = getPropertyMapValue(properties, SERVICE_MAPPING, parent.serviceMapping); + spanTags = getPropertyMapValue(properties, SPAN_TAGS, parent.spanTags); + headerTags = getPropertyMapValue(properties, HEADER_TAGS, parent.headerTags); + } + + private static String getSettingFromEnvironment(final String name, final String defaultValue) { + final String completeName = PREFIX + name; + final String value = + System.getProperties() + .getProperty(completeName, System.getenv(propertyToEnvironmentName(completeName))); + return value == null ? defaultValue : value; + } + + private static Map getMapSettingFromEnvironment( + final String name, final String defaultValue) { + return parseMap(getSettingFromEnvironment(name, defaultValue), PREFIX + name); + } + + private static String propertyToEnvironmentName(final String name) { + return name.toUpperCase().replace(".", "_"); + } + + private static Map getPropertyMapValue( + final Properties properties, final String name, final Map defaultValue) { + final String value = properties.getProperty(name); + return value == null ? defaultValue : parseMap(value, name); + } + + private static Map parseMap(final String str, final String settingName) { + if (str == null || str.trim().isEmpty()) { + return Collections.emptyMap(); + } + if (!str.matches("(([^,:]+:[^,:]*,)*([^,:]+:[^,:]*),?)?")) { + log.warn( + "Invalid config for {}: '{}'. Must match 'key1:value1,key2:value2'.", settingName, str); + return Collections.emptyMap(); + } + + final String[] tokens = str.split(",", -1); + final Map map = new HashMap<>(tokens.length + 1, 1f); + + for (final String token : tokens) { + final String[] keyValue = token.split(":", -1); + if (keyValue.length == 2) { + final String key = keyValue[0].trim(); + final String value = keyValue[1].trim(); + if (value.length() <= 0) { + log.warn("Ignoring empty value for key '{}' in config for {}", key, settingName); + continue; + } + map.put(key, value); + } + } + return Collections.unmodifiableMap(map); + } + + public static Config get() { + return INSTANCE; + } + + public static Config get(final Properties properties) { + if (properties == null || properties.isEmpty()) { + return INSTANCE; + } else { + return new Config(properties, INSTANCE); + } + } +} diff --git a/dd-trace-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/dd-trace-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy new file mode 100644 index 0000000000..cd2146f255 --- /dev/null +++ b/dd-trace-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -0,0 +1,183 @@ +package datadog.trace.api + +import org.junit.Rule +import org.junit.contrib.java.lang.system.EnvironmentVariables +import org.junit.contrib.java.lang.system.RestoreSystemProperties +import spock.lang.Specification + +import static Config.AGENT_HOST +import static Config.AGENT_PORT +import static Config.HEADER_TAGS +import static Config.PREFIX +import static Config.SERVICE_MAPPING +import static Config.SERVICE_NAME +import static Config.SPAN_TAGS +import static Config.WRITER_TYPE + +class ConfigTest extends Specification { + @Rule + public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties() + @Rule + public final EnvironmentVariables environmentVariables = new EnvironmentVariables() + + private static final DD_SERVICE_NAME_ENV = "DD_SERVICE_NAME" + private static final DD_WRITER_TYPE_ENV = "DD_WRITER_TYPE" + private static final DD_SERVICE_MAPPING_ENV = "DD_SERVICE_MAPPING" + private static final DD_SPAN_TAGS_ENV = "DD_SPAN_TAGS" + private static final DD_HEADER_TAGS_ENV = "DD_HEADER_TAGS" + + def "verify defaults"() { + when: + def config = Config.get() + + then: + config.serviceName == "unnamed-java-app" + config.serviceMapping == [:] + config.writerType == "DDAgentWriter" + config.prioritySamplingEnabled == false + config.agentHost == "localhost" + config.agentPort == 8126 + config.spanTags == [:] + config.toString().contains("unnamed-java-app") + } + + def "specify overrides via system properties"() { + setup: + System.setProperty(PREFIX + SERVICE_NAME, "something else") + System.setProperty(PREFIX + WRITER_TYPE, "LoggingWriter") + + when: + def config = new Config() + + then: + config.serviceName == "something else" + config.writerType == "LoggingWriter" + } + + def "specify overrides via env vars"() { + setup: + environmentVariables.set(DD_SERVICE_NAME_ENV, "still something else") + environmentVariables.set(DD_WRITER_TYPE_ENV, "LoggingWriter") + + when: + def config = new Config() + + then: + config.serviceName == "still something else" + config.writerType == "LoggingWriter" + } + + def "sys props override env vars"() { + setup: + environmentVariables.set(DD_SERVICE_NAME_ENV, "still something else") + environmentVariables.set(DD_WRITER_TYPE_ENV, "LoggingWriter") + + System.setProperty(PREFIX + SERVICE_NAME, "what we actually want") + System.setProperty(PREFIX + WRITER_TYPE, "DDAgentWriter") + System.setProperty(PREFIX + AGENT_HOST, "somewhere") + System.setProperty(PREFIX + AGENT_PORT, "9999") + + when: + def config = new Config() + + then: + config.serviceName == "what we actually want" + config.writerType == "DDAgentWriter" + config.agentHost == "somewhere" + config.agentPort == 9999 + } + + def "sys props override properties"() { + setup: + Properties properties = new Properties() + properties.setProperty(SERVICE_NAME, "what we actually want") + properties.setProperty(WRITER_TYPE, "DDAgentWriter") + properties.setProperty(AGENT_HOST, "somewhere") + properties.setProperty(AGENT_PORT, "9999") + + when: + def config = Config.get(properties) + + then: + config.serviceName == "what we actually want" + config.writerType == "DDAgentWriter" + config.agentHost == "somewhere" + config.agentPort == 9999 + } + + def "sys props override null properties"() { + when: + def config = Config.get(null) + + then: + config.serviceName == "unnamed-java-app" + config.writerType == "DDAgentWriter" + } + + def "sys props override empty properties"() { + setup: + Properties properties = new Properties() + + when: + def config = Config.get(properties) + + then: + config.serviceName == "unnamed-java-app" + config.writerType == "DDAgentWriter" + } + + def "verify mapping configs on tracer"() { + setup: + System.setProperty(PREFIX + SERVICE_MAPPING, mapString) + System.setProperty(PREFIX + SPAN_TAGS, mapString) + System.setProperty(PREFIX + HEADER_TAGS, mapString) + + when: + def config = new Config() + + then: + config.serviceMapping == map + config.spanTags == map + config.headerTags == map + + where: + mapString | map + "a:1, a:2, a:3" | [a: "3"] + "a:b,c:d,e:" | [a: "b", c: "d"] + // More different string variants: + "a:" | [:] + "a:a;" | [a: "a;"] + "a:1, a:2, a:3" | [a: "3"] + "a:b,c:d,e:" | [a: "b", c: "d"] + "key 1!:va|ue_1," | ["key 1!": "va|ue_1"] + " key1 :value1 ,\t key2: value2" | [key1: "value1", key2: "value2"] + // Invalid strings: + "" | [:] + "1" | [:] + "a" | [:] + "a,1" | [:] + "in:val:id" | [:] + "a:b:c:d" | [:] + "a:b,c,d" | [:] + "!a" | [:] + } + + def "verify null value mapping configs on tracer"() { + setup: + environmentVariables.set(DD_SERVICE_MAPPING_ENV, mapString) + environmentVariables.set(DD_SPAN_TAGS_ENV, mapString) + environmentVariables.set(DD_HEADER_TAGS_ENV, mapString) + + when: + def config = new Config() + + then: + config.serviceMapping == map + config.spanTags == map + config.headerTags == map + + where: + mapString | map + null | [:] + } +} diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java b/dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java index 62a2ad25d2..807e636fe7 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java @@ -1,11 +1,5 @@ package datadog.opentracing; -import static datadog.trace.common.DDTraceConfig.HEADER_TAGS; -import static datadog.trace.common.DDTraceConfig.SERVICE_MAPPING; -import static datadog.trace.common.DDTraceConfig.SERVICE_NAME; -import static datadog.trace.common.DDTraceConfig.SPAN_TAGS; -import static datadog.trace.common.util.Config.parseMap; - import datadog.opentracing.decorators.AbstractDecorator; import datadog.opentracing.decorators.DDDecoratorsFactory; import datadog.opentracing.propagation.Codec; @@ -13,11 +7,10 @@ import datadog.opentracing.propagation.ExtractedContext; import datadog.opentracing.propagation.HTTPCodec; import datadog.opentracing.scopemanager.ContextualScopeManager; import datadog.opentracing.scopemanager.ScopeContext; +import datadog.trace.api.Config; import datadog.trace.api.interceptor.MutableSpan; import datadog.trace.api.interceptor.TraceInterceptor; import datadog.trace.api.sampling.PrioritySampling; -import datadog.trace.common.DDTraceConfig; -import datadog.trace.common.sampling.AllSampler; import datadog.trace.common.sampling.RateByServiceSampler; import datadog.trace.common.sampling.Sampler; import datadog.trace.common.writer.DDAgentWriter; @@ -50,8 +43,6 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace.api.Tracer { - public static final String UNASSIGNED_DEFAULT_SERVICE_NAME = "unnamed-java-app"; - /** Default service name if none provided on the trace or span */ final String serviceName; /** Writer is an charge of reporting traces and spans to the desired endpoint */ @@ -84,21 +75,29 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace /** By default, report to local agent and collect all traces. */ public DDTracer() { - this(new DDTraceConfig()); + this(Config.get()); } public DDTracer(final String serviceName) { - this(new DDTraceConfig(serviceName)); + this(serviceName, Config.get()); } public DDTracer(final Properties config) { + this(Config.get(config)); + } + + public DDTracer(final Config config) { + this(config.getServiceName(), config); + } + + private DDTracer(final String serviceName, final Config config) { this( - config.getProperty(SERVICE_NAME), + serviceName, Writer.Builder.forConfig(config), Sampler.Builder.forConfig(config), - parseMap(config.getProperty(SPAN_TAGS), SPAN_TAGS), - parseMap(config.getProperty(SERVICE_MAPPING), SERVICE_MAPPING), - parseMap(config.getProperty(HEADER_TAGS), HEADER_TAGS)); + config.getSpanTags(), + config.getServiceMapping(), + config.getHeaderTags()); log.debug("Using config: {}", config); } @@ -112,6 +111,20 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace Collections.emptyMap()); } + public DDTracer(final Writer writer) { + this(Config.get(), writer); + } + + public DDTracer(final Config config, final Writer writer) { + this( + config.getServiceName(), + writer, + Sampler.Builder.forConfig(config), + config.getSpanTags(), + config.getServiceMapping(), + config.getHeaderTags()); + } + public DDTracer( final String serviceName, final Writer writer, @@ -154,8 +167,7 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace registerClassLoader(ClassLoader.getSystemClassLoader()); - final List decorators = - DDDecoratorsFactory.createBuiltinDecorators(serviceNameMappings); + final List decorators = DDDecoratorsFactory.createBuiltinDecorators(); for (final AbstractDecorator decorator : decorators) { log.debug("Loading decorator: {}", decorator.getClass().getSimpleName()); addDecorator(decorator); @@ -164,16 +176,6 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace log.info("New instance: {}", this); } - public DDTracer(final Writer writer) { - this( - UNASSIGNED_DEFAULT_SERVICE_NAME, - writer, - new AllSampler(), - parseMap(new DDTraceConfig().getProperty(SPAN_TAGS), SPAN_TAGS), - parseMap(new DDTraceConfig().getProperty(SERVICE_MAPPING), SPAN_TAGS), - parseMap(new DDTraceConfig().getProperty(HEADER_TAGS), SPAN_TAGS)); - } - /** * Returns the list of span context decorators * @@ -296,7 +298,7 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace @Override public String getTraceId() { - final Span activeSpan = this.activeSpan(); + final Span activeSpan = activeSpan(); if (activeSpan instanceof DDSpan) { return ((DDSpan) activeSpan).getTraceId(); } @@ -305,7 +307,7 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace @Override public String getSpanId() { - final Span activeSpan = this.activeSpan(); + final Span activeSpan = activeSpan(); if (activeSpan instanceof DDSpan) { return ((DDSpan) activeSpan).getSpanId(); } diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/decorators/DDDecoratorsFactory.java b/dd-trace-ot/src/main/java/datadog/opentracing/decorators/DDDecoratorsFactory.java index 58a69797c8..61bd648e1b 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/decorators/DDDecoratorsFactory.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/decorators/DDDecoratorsFactory.java @@ -2,12 +2,10 @@ package datadog.opentracing.decorators; import java.util.Arrays; import java.util.List; -import java.util.Map; /** Create DDSpanDecorators */ public class DDDecoratorsFactory { - public static List createBuiltinDecorators( - final Map mappings) { + public static List createBuiltinDecorators() { final HTTPComponent httpDecorator = new HTTPComponent(); httpDecorator.setMatchingTag("component"); httpDecorator.setMatchingValue("java-aws-sdk"); diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/decorators/ServletContextDecorator.java b/dd-trace-ot/src/main/java/datadog/opentracing/decorators/ServletContextDecorator.java index 956daa751b..d0ee80531b 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/decorators/ServletContextDecorator.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/decorators/ServletContextDecorator.java @@ -1,20 +1,20 @@ package datadog.opentracing.decorators; import datadog.opentracing.DDSpanContext; -import datadog.opentracing.DDTracer; +import datadog.trace.api.Config; public class ServletContextDecorator extends AbstractDecorator { public ServletContextDecorator() { super(); - this.setMatchingTag("servlet.context"); + setMatchingTag("servlet.context"); } @Override public boolean shouldSetTag(final DDSpanContext context, final String tag, final Object value) { String contextName = String.valueOf(value).trim(); if (contextName.equals("/") - || (!context.getServiceName().equals(DDTracer.UNASSIGNED_DEFAULT_SERVICE_NAME) + || (!context.getServiceName().equals(Config.DEFAULT_SERVICE_NAME) && !context.getServiceName().isEmpty())) { return true; } diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/resolver/DDTracerResolver.java b/dd-trace-ot/src/main/java/datadog/opentracing/resolver/DDTracerResolver.java index b440b44684..571323780b 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/resolver/DDTracerResolver.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/resolver/DDTracerResolver.java @@ -1,36 +1,20 @@ package datadog.opentracing.resolver; import com.google.auto.service.AutoService; +import com.google.common.annotations.VisibleForTesting; import datadog.opentracing.DDTracer; -import datadog.trace.common.util.Config; +import datadog.trace.api.Config; import io.opentracing.Tracer; import io.opentracing.contrib.tracerresolver.TracerResolver; -import io.opentracing.noop.NoopTracerFactory; -import io.opentracing.util.GlobalTracer; import lombok.extern.slf4j.Slf4j; @Slf4j @AutoService(TracerResolver.class) public class DDTracerResolver extends TracerResolver { - static final String CONFIG_KEY = "dd.trace.resolver.enabled"; - public static Tracer registerTracer() { - final Tracer tracer = TracerResolver.resolveTracer(); - - if (tracer == null) { - log.warn("Cannot resolved the tracer, use NoopTracer"); - return NoopTracerFactory.create(); - } - - log.info("Register the tracer via GlobalTracer"); - GlobalTracer.register(tracer); - return tracer; - } - - @Override - protected Tracer resolve() { - final boolean enabled = !"false".equalsIgnoreCase(Config.getPropOrEnv(CONFIG_KEY)); - if (enabled) { + @VisibleForTesting + Tracer resolve(final Config config) { + if (config.isTraceResolverEnabled()) { log.info("Creating DDTracer with DDTracerResolver"); return new DDTracer(); } else { @@ -38,4 +22,9 @@ public class DDTracerResolver extends TracerResolver { return null; } } + + @Override + protected Tracer resolve() { + return resolve(Config.get()); + } } diff --git a/dd-trace-ot/src/main/java/datadog/trace/common/DDTraceConfig.java b/dd-trace-ot/src/main/java/datadog/trace/common/DDTraceConfig.java deleted file mode 100644 index 4587a8dd4b..0000000000 --- a/dd-trace-ot/src/main/java/datadog/trace/common/DDTraceConfig.java +++ /dev/null @@ -1,73 +0,0 @@ -package datadog.trace.common; - -import static datadog.trace.common.util.Config.getPropOrEnv; - -import datadog.opentracing.DDTracer; -import datadog.trace.common.writer.DDAgentWriter; -import datadog.trace.common.writer.Writer; -import java.util.Properties; -import lombok.extern.slf4j.Slf4j; - -/** - * Config gives priority to system properties and falls back to environment variables. It also - * includes default values to ensure a valid config. - * - *

- * - *

System properties are {@link DDTraceConfig#PREFIX}'ed. Environment variables are the same as - * the system property, but uppercased with '.' -> '_'. - */ -@Slf4j -public class DDTraceConfig extends Properties { - /** Config keys below */ - private static final String PREFIX = "dd."; - - public static final String SERVICE_NAME = "service.name"; - public static final String SERVICE_MAPPING = "service.mapping"; - public static final String WRITER_TYPE = "writer.type"; - public static final String AGENT_HOST = "agent.host"; - public static final String AGENT_PORT = "agent.port"; - public static final String PRIORITY_SAMPLING = "priority.sampling"; - public static final String SPAN_TAGS = "trace.span.tags"; - public static final String HEADER_TAGS = "trace.header.tags"; - - private final String serviceName = getPropOrEnv(PREFIX + SERVICE_NAME); - private final String serviceMapping = getPropOrEnv(PREFIX + SERVICE_MAPPING); - private final String writerType = getPropOrEnv(PREFIX + WRITER_TYPE); - private final String agentHost = getPropOrEnv(PREFIX + AGENT_HOST); - private final String agentPort = getPropOrEnv(PREFIX + AGENT_PORT); - private final String prioritySampling = getPropOrEnv(PREFIX + PRIORITY_SAMPLING); - private final String spanTags = getPropOrEnv(PREFIX + SPAN_TAGS); - private final String headerTags = getPropOrEnv(PREFIX + HEADER_TAGS); - - public DDTraceConfig() { - super(); - - final Properties defaults = new Properties(); - defaults.setProperty(SERVICE_NAME, DDTracer.UNASSIGNED_DEFAULT_SERVICE_NAME); - defaults.setProperty(WRITER_TYPE, Writer.DD_AGENT_WRITER_TYPE); - defaults.setProperty(AGENT_HOST, DDAgentWriter.DEFAULT_HOSTNAME); - defaults.setProperty(AGENT_PORT, String.valueOf(DDAgentWriter.DEFAULT_PORT)); - super.defaults = defaults; - - setIfNotNull(SERVICE_NAME, serviceName); - setIfNotNull(SERVICE_MAPPING, serviceMapping); - setIfNotNull(WRITER_TYPE, writerType); - setIfNotNull(AGENT_HOST, agentHost); - setIfNotNull(AGENT_PORT, agentPort); - setIfNotNull(PRIORITY_SAMPLING, prioritySampling); - setIfNotNull(SPAN_TAGS, spanTags); - setIfNotNull(HEADER_TAGS, headerTags); - } - - public DDTraceConfig(final String serviceName) { - this(); - put(SERVICE_NAME, serviceName); - } - - private void setIfNotNull(final String key, final String value) { - if (value != null) { - setProperty(key, value); - } - } -} diff --git a/dd-trace-ot/src/main/java/datadog/trace/common/sampling/Sampler.java b/dd-trace-ot/src/main/java/datadog/trace/common/sampling/Sampler.java index 5d27359389..072a05f361 100644 --- a/dd-trace-ot/src/main/java/datadog/trace/common/sampling/Sampler.java +++ b/dd-trace-ot/src/main/java/datadog/trace/common/sampling/Sampler.java @@ -1,12 +1,11 @@ package datadog.trace.common.sampling; import datadog.opentracing.DDSpan; -import datadog.trace.common.DDTraceConfig; +import datadog.trace.api.Config; import java.util.Properties; /** Main interface to sample a collection of traces. */ public interface Sampler { - static final String ALL_SAMPLER_TYPE = AllSampler.class.getSimpleName(); /** * Sample a collection of traces based on the parent span @@ -17,12 +16,10 @@ public interface Sampler { boolean sample(DDSpan span); final class Builder { - public static Sampler forConfig(final Properties config) { + public static Sampler forConfig(final Config config) { final Sampler sampler; if (config != null) { - final boolean prioritySamplingEnabled = - Boolean.parseBoolean(config.getProperty(DDTraceConfig.PRIORITY_SAMPLING)); - if (prioritySamplingEnabled) { + if (config.isPrioritySamplingEnabled()) { sampler = new RateByServiceSampler(); } else { sampler = new AllSampler(); @@ -33,6 +30,10 @@ public interface Sampler { return sampler; } + public static Sampler forConfig(final Properties config) { + return forConfig(Config.get(config)); + } + private Builder() {} } } diff --git a/dd-trace-ot/src/main/java/datadog/trace/common/util/Config.java b/dd-trace-ot/src/main/java/datadog/trace/common/util/Config.java deleted file mode 100644 index 2482f2ebfa..0000000000 --- a/dd-trace-ot/src/main/java/datadog/trace/common/util/Config.java +++ /dev/null @@ -1,46 +0,0 @@ -package datadog.trace.common.util; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public abstract class Config { - - public static String getPropOrEnv(final String name) { - return System.getProperty(name, System.getenv(propToEnvName(name))); - } - - public static String propToEnvName(final String name) { - return name.toUpperCase().replace(".", "_"); - } - - public static Map parseMap(final String str, final String settingName) { - if (str == null || str.trim().isEmpty()) { - return Collections.emptyMap(); - } - if (!str.matches("(([^,:]+:[^,:]*,)*([^,:]+:[^,:]*),?)?")) { - log.warn( - "Invalid config for {}: '{}'. Must match 'key1:value1,key2:value2'.", settingName, str); - return Collections.emptyMap(); - } - - final String[] tokens = str.split(",", -1); - final Map map = new HashMap<>(tokens.length + 1, 1f); - - for (final String token : tokens) { - final String[] keyValue = token.split(":", -1); - if (keyValue.length == 2) { - final String key = keyValue[0].trim(); - final String value = keyValue[1].trim(); - if (value.length() <= 0) { - log.warn("Ignoring empty value for key '{}' in config for {}", key, settingName); - continue; - } - map.put(key, value); - } - } - return Collections.unmodifiableMap(map); - } -} diff --git a/dd-trace-ot/src/main/java/datadog/trace/common/writer/DDAgentWriter.java b/dd-trace-ot/src/main/java/datadog/trace/common/writer/DDAgentWriter.java index 57c874a971..cd9e53fc2c 100644 --- a/dd-trace-ot/src/main/java/datadog/trace/common/writer/DDAgentWriter.java +++ b/dd-trace-ot/src/main/java/datadog/trace/common/writer/DDAgentWriter.java @@ -1,5 +1,8 @@ package datadog.trace.common.writer; +import static datadog.trace.api.Config.DEFAULT_AGENT_HOST; +import static datadog.trace.api.Config.DEFAULT_AGENT_PORT; + import datadog.opentracing.DDSpan; import java.util.List; import java.util.concurrent.Callable; @@ -25,11 +28,6 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class DDAgentWriter implements Writer { - /** Default location of the DD agent */ - public static final String DEFAULT_HOSTNAME = "localhost"; - - public static final int DEFAULT_PORT = 8126; - /** Maximum number of traces kept in memory */ static final int DEFAULT_MAX_TRACES = 7000; @@ -66,7 +64,7 @@ public class DDAgentWriter implements Writer { private boolean queueFullReported = false; public DDAgentWriter() { - this(new DDApi(DEFAULT_HOSTNAME, DEFAULT_PORT)); + this(new DDApi(DEFAULT_AGENT_HOST, DEFAULT_AGENT_PORT)); } public DDAgentWriter(final DDApi api) { diff --git a/dd-trace-ot/src/main/java/datadog/trace/common/writer/Writer.java b/dd-trace-ot/src/main/java/datadog/trace/common/writer/Writer.java index 52df8fd0f4..d73c764aa0 100644 --- a/dd-trace-ot/src/main/java/datadog/trace/common/writer/Writer.java +++ b/dd-trace-ot/src/main/java/datadog/trace/common/writer/Writer.java @@ -1,15 +1,13 @@ package datadog.trace.common.writer; import datadog.opentracing.DDSpan; -import datadog.trace.common.DDTraceConfig; +import datadog.trace.api.Config; import java.util.List; import java.util.Properties; import lombok.extern.slf4j.Slf4j; /** A writer is responsible to send collected spans to some place */ public interface Writer { - static final String DD_AGENT_WRITER_TYPE = DDAgentWriter.class.getSimpleName(); - static final String LOGGING_WRITER_TYPE = LoggingWriter.class.getSimpleName(); /** * Write a trace represented by the entire list of all the finished spans @@ -29,28 +27,21 @@ public interface Writer { @Slf4j final class Builder { - public static Writer forConfig(final Properties config) { + + public static Writer forConfig(final Config config) { final Writer writer; if (config != null) { - final String configuredType = config.getProperty(DDTraceConfig.WRITER_TYPE); - if (DD_AGENT_WRITER_TYPE.equals(configuredType)) { - writer = - new DDAgentWriter( - new DDApi( - config.getProperty(DDTraceConfig.AGENT_HOST), - Integer.parseInt(config.getProperty(DDTraceConfig.AGENT_PORT)))); - } else if (LOGGING_WRITER_TYPE.equals(configuredType)) { + final String configuredType = config.getWriterType(); + if (Config.DD_AGENT_WRITER_TYPE.equals(configuredType)) { + writer = createAgentWriter(config); + } else if (Config.LOGGING_WRITER_TYPE.equals(configuredType)) { writer = new LoggingWriter(); } else { log.warn( "Writer type not configured correctly: Type {} not recognized. Defaulting to DDAgentWriter.", configuredType); - writer = - new DDAgentWriter( - new DDApi( - config.getProperty(DDTraceConfig.AGENT_HOST), - Integer.parseInt(config.getProperty(DDTraceConfig.AGENT_PORT)))); + writer = createAgentWriter(config); } } else { log.warn( @@ -61,6 +52,14 @@ public interface Writer { return writer; } + public static Writer forConfig(final Properties config) { + return forConfig(Config.get(config)); + } + + private static Writer createAgentWriter(final Config config) { + return new DDAgentWriter(new DDApi(config.getAgentHost(), config.getAgentPort())); + } + private Builder() {} } } diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanBuilderTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanBuilderTest.groovy index 02445940d8..dc3e54119a 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanBuilderTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanBuilderTest.groovy @@ -1,6 +1,7 @@ package datadog.opentracing import datadog.opentracing.propagation.ExtractedContext +import datadog.trace.api.Config import datadog.trace.api.DDTags import datadog.trace.common.writer.ListWriter import spock.lang.Specification @@ -273,7 +274,7 @@ class DDSpanBuilderTest extends Specification { def "global span tags populated on each span"() { setup: System.setProperty("dd.trace.span.tags", tagString) - tracer = new DDTracer(writer) + tracer = new DDTracer(new Config(), writer) def span = tracer.buildSpan("op name").withServiceName("foo").start() tags.putAll([ (DDTags.THREAD_NAME): Thread.currentThread().getName(), diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanTest.groovy index 9abd211321..66497c6fa4 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanTest.groovy @@ -7,9 +7,11 @@ import spock.lang.Specification import java.util.concurrent.TimeUnit +import static datadog.trace.api.Config.DEFAULT_SERVICE_NAME + class DDSpanTest extends Specification { def writer = new ListWriter() - def tracer = new DDTracer(DDTracer.UNASSIGNED_DEFAULT_SERVICE_NAME, writer, new RateByServiceSampler()) + def tracer = new DDTracer(DEFAULT_SERVICE_NAME, writer, new RateByServiceSampler()) def "getters and setters"() { setup: @@ -77,7 +79,7 @@ class DDSpanTest extends Specification { span = tracer.buildSpan(opName).start() then: span.getResourceName() == opName - span.getServiceName() == DDTracer.UNASSIGNED_DEFAULT_SERVICE_NAME + span.getServiceName() == DEFAULT_SERVICE_NAME when: final String resourceName = "fake" diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/decorators/SpanDecoratorTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/decorators/SpanDecoratorTest.groovy index b471a01f78..376ed333a5 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/decorators/SpanDecoratorTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/decorators/SpanDecoratorTest.groovy @@ -11,7 +11,7 @@ import io.opentracing.tag.StringTag import io.opentracing.tag.Tags import spock.lang.Specification -import static datadog.opentracing.DDTracer.UNASSIGNED_DEFAULT_SERVICE_NAME +import static datadog.trace.api.Config.DEFAULT_SERVICE_NAME import static java.util.Collections.emptyMap class SpanDecoratorTest extends Specification { @@ -75,10 +75,10 @@ class SpanDecoratorTest extends Specification { span.serviceName == expected where: - serviceName | expected | mapping - UNASSIGNED_DEFAULT_SERVICE_NAME | UNASSIGNED_DEFAULT_SERVICE_NAME | ["other-service-name": "other-service"] - UNASSIGNED_DEFAULT_SERVICE_NAME | "new-service" | [(UNASSIGNED_DEFAULT_SERVICE_NAME): "new-service"] - "other-service-name" | "other-service" | ["other-service-name": "other-service"] + serviceName | expected | mapping + DEFAULT_SERVICE_NAME | DEFAULT_SERVICE_NAME | ["other-service-name": "other-service"] + DEFAULT_SERVICE_NAME | "new-service" | [(DEFAULT_SERVICE_NAME): "new-service"] + "other-service-name" | "other-service" | ["other-service-name": "other-service"] } def "set service name from servlet.context with context '#context'"() { @@ -90,15 +90,15 @@ class SpanDecoratorTest extends Specification { span.serviceName == expected where: - context | serviceName | expected - "/" | UNASSIGNED_DEFAULT_SERVICE_NAME | UNASSIGNED_DEFAULT_SERVICE_NAME - "" | UNASSIGNED_DEFAULT_SERVICE_NAME | UNASSIGNED_DEFAULT_SERVICE_NAME - "/some-context" | UNASSIGNED_DEFAULT_SERVICE_NAME | "some-context" - "other-context" | UNASSIGNED_DEFAULT_SERVICE_NAME | "other-context" - "/" | "my-service" | "my-service" - "" | "my-service" | "my-service" - "/some-context" | "my-service" | "my-service" - "other-context" | "my-service" | "my-service" + context | serviceName | expected + "/" | DEFAULT_SERVICE_NAME | DEFAULT_SERVICE_NAME + "" | DEFAULT_SERVICE_NAME | DEFAULT_SERVICE_NAME + "/some-context" | DEFAULT_SERVICE_NAME | "some-context" + "other-context" | DEFAULT_SERVICE_NAME | "other-context" + "/" | "my-service" | "my-service" + "" | "my-service" | "my-service" + "/some-context" | "my-service" | "my-service" + "other-context" | "my-service" | "my-service" } def "set service name from servlet.context with context '#context' for service #serviceName"() { @@ -114,15 +114,15 @@ class SpanDecoratorTest extends Specification { span.serviceName == expected where: - context | serviceName | expected - "/" | UNASSIGNED_DEFAULT_SERVICE_NAME | "new-service" - "" | UNASSIGNED_DEFAULT_SERVICE_NAME | "new-service" - "/some-context" | UNASSIGNED_DEFAULT_SERVICE_NAME | "some-context" - "other-context" | UNASSIGNED_DEFAULT_SERVICE_NAME | "other-context" - "/" | "my-service" | "new-service" - "" | "my-service" | "new-service" - "/some-context" | "my-service" | "new-service" - "other-context" | "my-service" | "new-service" + context | serviceName | expected + "/" | DEFAULT_SERVICE_NAME | "new-service" + "" | DEFAULT_SERVICE_NAME | "new-service" + "/some-context" | DEFAULT_SERVICE_NAME | "some-context" + "other-context" | DEFAULT_SERVICE_NAME | "other-context" + "/" | "my-service" | "new-service" + "" | "my-service" | "new-service" + "/some-context" | "my-service" | "new-service" + "other-context" | "my-service" | "new-service" mapping = [(serviceName): "new-service"] } diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/resolver/DDTracerResolverTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/resolver/DDTracerResolverTest.groovy new file mode 100644 index 0000000000..e45985630d --- /dev/null +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/resolver/DDTracerResolverTest.groovy @@ -0,0 +1,34 @@ +package datadog.opentracing.resolver + +import datadog.opentracing.DDTracer +import datadog.trace.api.Config +import io.opentracing.contrib.tracerresolver.TracerResolver +import spock.lang.Specification + +class DDTracerResolverTest extends Specification { + + def resolver = new DDTracerResolver() + + def "test resolveTracer"() { + when: + def tracer = TracerResolver.resolveTracer() + + then: + tracer instanceof DDTracer + } + + def "test disable DDTracerResolver"() { + setup: + System.setProperty("dd.trace.resolver.enabled", "false") + + when: + def tracer = resolver.resolve(new Config()) + + then: + tracer == null + + cleanup: + System.clearProperty("dd.trace.resolver.enabled") + } + +} diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/resolver/TracerResolverTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/resolver/TracerResolverTest.groovy deleted file mode 100644 index 53410b7481..0000000000 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/resolver/TracerResolverTest.groovy +++ /dev/null @@ -1,65 +0,0 @@ -package datadog.opentracing.resolver - -import datadog.opentracing.DDTracer -import io.opentracing.Tracer -import io.opentracing.contrib.tracerresolver.TracerResolver -import io.opentracing.noop.NoopTracer -import io.opentracing.noop.NoopTracerFactory -import io.opentracing.util.GlobalTracer -import spock.lang.Specification - -import java.lang.reflect.Field - -class TracerResolverTest extends Specification { - - def setup() { - setTracer(null) - assert !GlobalTracer.isRegistered() - } - - def "test resolveTracer"() { - when: - def tracer = TracerResolver.resolveTracer() - - then: - !GlobalTracer.isRegistered() - tracer instanceof DDTracer - } - - def "test registerTracer"() { - when: - def tracer = DDTracerResolver.registerTracer() - - then: - GlobalTracer.isRegistered() - tracer instanceof DDTracer - } - - def "test disable DDTracerResolver"() { - setup: - System.setProperty("dd.trace.resolver.enabled", "false") - - when: - def tracer = TracerResolver.resolveTracer() - - then: - !GlobalTracer.isRegistered() - tracer == null - - when: - tracer = DDTracerResolver.registerTracer() - - then: - !GlobalTracer.isRegistered() - tracer instanceof NoopTracer - - cleanup: - System.clearProperty("dd.trace.resolver.enabled") - } - - def setTracer(Tracer tracer) { - final Field tracerField = GlobalTracer.getDeclaredField("tracer") - tracerField.setAccessible(true) - tracerField.set(tracer, NoopTracerFactory.create()) - } -} diff --git a/dd-trace-ot/src/test/groovy/datadog/trace/DDTraceConfigTest.groovy b/dd-trace-ot/src/test/groovy/datadog/trace/DDTraceConfigTest.groovy deleted file mode 100644 index fbc990693e..0000000000 --- a/dd-trace-ot/src/test/groovy/datadog/trace/DDTraceConfigTest.groovy +++ /dev/null @@ -1,182 +0,0 @@ -package datadog.trace - -import datadog.opentracing.DDTracer -import datadog.trace.common.DDTraceConfig -import datadog.trace.common.sampling.AllSampler -import datadog.trace.common.writer.DDAgentWriter -import datadog.trace.common.writer.ListWriter -import datadog.trace.common.writer.LoggingWriter -import org.junit.Rule -import org.junit.contrib.java.lang.system.EnvironmentVariables -import org.junit.contrib.java.lang.system.RestoreSystemProperties -import spock.lang.Specification - -import static datadog.trace.common.DDTraceConfig.AGENT_HOST -import static datadog.trace.common.DDTraceConfig.AGENT_PORT -import static datadog.trace.common.DDTraceConfig.HEADER_TAGS -import static datadog.trace.common.DDTraceConfig.PREFIX -import static datadog.trace.common.DDTraceConfig.SERVICE_MAPPING -import static datadog.trace.common.DDTraceConfig.SERVICE_NAME -import static datadog.trace.common.DDTraceConfig.SPAN_TAGS -import static datadog.trace.common.DDTraceConfig.WRITER_TYPE -import static datadog.trace.common.util.Config.parseMap -import static datadog.trace.common.util.Config.propToEnvName - -class DDTraceConfigTest extends Specification { - @Rule - public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties() - @Rule - public final EnvironmentVariables environmentVariables = new EnvironmentVariables() - - def "verify env override"() { - setup: - environmentVariables.set("SOME_RANDOM_ENTRY", "asdf") - - expect: - System.getenv("SOME_RANDOM_ENTRY") == "asdf" - } - - def "verify defaults"() { - when: - def config = new DDTraceConfig() - - then: - config.getProperty(SERVICE_NAME) == "unnamed-java-app" - config.getProperty(SERVICE_MAPPING) == null - config.getProperty(WRITER_TYPE) == "DDAgentWriter" - config.getProperty(AGENT_HOST) == "localhost" - config.getProperty(AGENT_PORT) == "8126" - config.getProperty(SPAN_TAGS) == null - - when: - config = new DDTraceConfig("A different service name") - - then: - config.getProperty(SERVICE_NAME) == "A different service name" - config.getProperty(SERVICE_MAPPING) == null - config.getProperty(WRITER_TYPE) == "DDAgentWriter" - config.getProperty(AGENT_HOST) == "localhost" - config.getProperty(AGENT_PORT) == "8126" - config.getProperty(SPAN_TAGS) == null - } - - def "specify overrides via system properties"() { - when: - System.setProperty(PREFIX + SERVICE_NAME, "something else") - System.setProperty(PREFIX + WRITER_TYPE, LoggingWriter.simpleName) - def tracer = new DDTracer() - - then: - tracer.serviceName == "something else" - tracer.writer instanceof LoggingWriter - } - - def "specify overrides via env vars"() { - when: - environmentVariables.set(propToEnvName(PREFIX + SERVICE_NAME), "still something else") - environmentVariables.set(propToEnvName(PREFIX + WRITER_TYPE), LoggingWriter.simpleName) - def tracer = new DDTracer() - - then: - tracer.serviceName == "still something else" - tracer.writer instanceof LoggingWriter - } - - def "sys props override env vars"() { - when: - environmentVariables.set(propToEnvName(PREFIX + SERVICE_NAME), "still something else") - environmentVariables.set(propToEnvName(PREFIX + WRITER_TYPE), ListWriter.simpleName) - - System.setProperty(PREFIX + SERVICE_NAME, "what we actually want") - System.setProperty(PREFIX + WRITER_TYPE, DDAgentWriter.simpleName) - System.setProperty(PREFIX + AGENT_HOST, "somewhere") - System.setProperty(PREFIX + AGENT_PORT, "9999") - - def tracer = new DDTracer() - - then: - tracer.serviceName == "what we actually want" - tracer.writer.toString() == "DDAgentWriter { api=DDApi { tracesEndpoint=http://somewhere:9999/v0.3/traces } }" - } - - def "verify defaults on tracer"() { - when: - def tracer = new DDTracer() - - then: - tracer.serviceName == "unnamed-java-app" - tracer.sampler instanceof AllSampler - tracer.writer.toString() == "DDAgentWriter { api=DDApi { tracesEndpoint=http://localhost:8126/v0.3/traces } }" - - tracer.spanContextDecorators.size() == 12 - } - - def "verify mapping configs on tracer"() { - setup: - System.setProperty(PREFIX + SERVICE_MAPPING, mapString) - System.setProperty(PREFIX + SPAN_TAGS, mapString) - System.setProperty(PREFIX + HEADER_TAGS, mapString) - - when: - def tracer = new DDTracer() - def taggedHeaders = tracer.registry.codecs.values().first().taggedHeaders - - then: - tracer.defaultSpanTags == map - tracer.serviceNameMappings == map - taggedHeaders == map - - where: - mapString | map - "a:1, a:2, a:3" | [a: "3"] - "a:b,c:d,e:" | [a: "b", c: "d"] - } - - def "verify single override on #source for #key"() { - when: - System.setProperty(PREFIX + key, value) - def tracer = new DDTracer() - - then: - tracer."$source".toString() == expected - - where: - - source | key | value | expected - "writer" | "default" | "default" | "DDAgentWriter { api=DDApi { tracesEndpoint=http://localhost:8126/v0.3/traces } }" - "writer" | "writer.type" | "LoggingWriter" | "LoggingWriter { }" - "writer" | "agent.host" | "somethingelse" | "DDAgentWriter { api=DDApi { tracesEndpoint=http://somethingelse:8126/v0.3/traces } }" - "writer" | "agent.port" | "9999" | "DDAgentWriter { api=DDApi { tracesEndpoint=http://localhost:9999/v0.3/traces } }" - } - - def "parsing valid string returns a map"() { - expect: - parseMap(str, "test") == map - - where: - str | map - "a:" | [:] - "a:a;" | [a: "a;"] - "a:1, a:2, a:3" | [a: "3"] - "a:b,c:d,e:" | [a: "b", c: "d"] - "key 1!:va|ue_1," | ["key 1!": "va|ue_1"] - " key1 :value1 ,\t key2: value2" | [key1: "value1", key2: "value2"] - } - - def "parsing an invalid string returns an empty map"() { - expect: - parseMap(str, "test") == [:] - - where: - str | _ - null | _ - "" | _ - "1" | _ - "a" | _ - "a,1" | _ - "in:val:id" | _ - "a:b:c:d" | _ - "a:b,c,d" | _ - "!a" | _ - } -} diff --git a/dd-trace-ot/src/test/groovy/datadog/trace/DDTracerTest.groovy b/dd-trace-ot/src/test/groovy/datadog/trace/DDTracerTest.groovy new file mode 100644 index 0000000000..bedeed286a --- /dev/null +++ b/dd-trace-ot/src/test/groovy/datadog/trace/DDTracerTest.groovy @@ -0,0 +1,97 @@ +package datadog.trace + +import datadog.opentracing.DDTracer +import datadog.trace.api.Config +import datadog.trace.common.sampling.AllSampler +import datadog.trace.common.sampling.RateByServiceSampler +import datadog.trace.common.writer.LoggingWriter +import org.junit.Rule +import org.junit.contrib.java.lang.system.EnvironmentVariables +import org.junit.contrib.java.lang.system.RestoreSystemProperties +import spock.lang.Specification + +import static datadog.trace.api.Config.HEADER_TAGS +import static datadog.trace.api.Config.PREFIX +import static datadog.trace.api.Config.PRIORITY_SAMPLING +import static datadog.trace.api.Config.SERVICE_MAPPING +import static datadog.trace.api.Config.SPAN_TAGS +import static datadog.trace.api.Config.WRITER_TYPE + +class DDTracerTest extends Specification { + @Rule + public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties() + @Rule + public final EnvironmentVariables environmentVariables = new EnvironmentVariables() + + def "verify defaults on tracer"() { + when: + def tracer = new DDTracer() + + then: + tracer.serviceName == "unnamed-java-app" + tracer.sampler instanceof AllSampler + tracer.writer.toString() == "DDAgentWriter { api=DDApi { tracesEndpoint=http://localhost:8126/v0.3/traces } }" + + tracer.spanContextDecorators.size() == 12 + } + + def "verify overriding sampler"() { + setup: + System.setProperty(PREFIX + PRIORITY_SAMPLING, "true") + + when: + def tracer = new DDTracer(new Config()) + + then: + tracer.sampler instanceof RateByServiceSampler + } + + def "verify overriding writer"() { + setup: + System.setProperty(PREFIX + WRITER_TYPE, "LoggingWriter") + + when: + def tracer = new DDTracer(new Config()) + + then: + tracer.writer instanceof LoggingWriter + } + + def "verify mapping configs on tracer"() { + setup: + System.setProperty(PREFIX + SERVICE_MAPPING, mapString) + System.setProperty(PREFIX + SPAN_TAGS, mapString) + System.setProperty(PREFIX + HEADER_TAGS, mapString) + + when: + def tracer = new DDTracer(new Config()) + def taggedHeaders = tracer.registry.codecs.values().first().taggedHeaders + + then: + tracer.defaultSpanTags == map + tracer.serviceNameMappings == map + taggedHeaders == map + + where: + mapString | map + "a:1, a:2, a:3" | [a: "3"] + "a:b,c:d,e:" | [a: "b", c: "d"] + } + + def "verify single override on #source for #key"() { + when: + System.setProperty(PREFIX + key, value) + def tracer = new DDTracer(new Config()) + + then: + tracer."$source".toString() == expected + + where: + + source | key | value | expected + "writer" | "default" | "default" | "DDAgentWriter { api=DDApi { tracesEndpoint=http://localhost:8126/v0.3/traces } }" + "writer" | "writer.type" | "LoggingWriter" | "LoggingWriter { }" + "writer" | "agent.host" | "somethingelse" | "DDAgentWriter { api=DDApi { tracesEndpoint=http://somethingelse:8126/v0.3/traces } }" + "writer" | "agent.port" | "9999" | "DDAgentWriter { api=DDApi { tracesEndpoint=http://localhost:9999/v0.3/traces } }" + } +} diff --git a/dd-trace-ot/src/traceAgentTest/groovy/DDApiIntegrationTest.groovy b/dd-trace-ot/src/traceAgentTest/groovy/DDApiIntegrationTest.groovy index 27d8e776a4..4e13a0923f 100644 --- a/dd-trace-ot/src/traceAgentTest/groovy/DDApiIntegrationTest.groovy +++ b/dd-trace-ot/src/traceAgentTest/groovy/DDApiIntegrationTest.groovy @@ -4,7 +4,6 @@ import datadog.opentracing.DDSpanContext import datadog.opentracing.DDTracer import datadog.opentracing.PendingTrace import datadog.trace.api.sampling.PrioritySampling -import datadog.trace.common.writer.DDAgentWriter import datadog.trace.common.writer.DDApi import datadog.trace.common.writer.ListWriter import spock.lang.Specification @@ -12,6 +11,9 @@ import spock.lang.Specification import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicReference +import static datadog.trace.api.Config.DEFAULT_AGENT_HOST +import static datadog.trace.api.Config.DEFAULT_AGENT_PORT + class DDApiIntegrationTest { static class DDApiIntegrationV4Test extends Specification { static final WRITER = new ListWriter() @@ -31,7 +33,7 @@ class DDApiIntegrationTest { new PendingTrace(TRACER, "1", [:]), TRACER) - def api = new DDApi(DDAgentWriter.DEFAULT_HOSTNAME, DDAgentWriter.DEFAULT_PORT, v4()) + def api = new DDApi(DEFAULT_AGENT_HOST, DEFAULT_AGENT_PORT, v4()) def endpoint = new AtomicReference(null) def agentResponse = new AtomicReference(null)