Merge pull request #827 from DataDog/labbati/hostname

Detect hostname
This commit is contained in:
Luca Abbati 2019-05-17 19:30:02 +02:00 committed by GitHub
commit 920b9b5ad3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 175 additions and 34 deletions

View File

@ -20,8 +20,8 @@ Other source files (Groovy, Scala, etc) should ideally be formatted by Intellij
Suggested plugins and settings: Suggested plugins and settings:
* Editor > Code Style > Java/Groovy > Imports * Editor > Code Style > Java/Groovy > Imports
* Class count to use import with '*': `10` (some number sufficiently large that is unlikely to matter) * Class count to use import with '*': `50` (some number sufficiently large that is unlikely to matter)
* Names count to use static import with '*': `10` * Names count to use static import with '*': `50`
* With java use the following import layout (groovy should still use the default) to ensure consistency with google-java-format: * With java use the following import layout (groovy should still use the default) to ensure consistency with google-java-format:
![import layout](https://user-images.githubusercontent.com/734411/43430811-28442636-94ae-11e8-86f1-f270ddcba023.png) ![import layout](https://user-images.githubusercontent.com/734411/43430811-28442636-94ae-11e8-86f1-f270ddcba023.png)
* [Google Java Format](https://plugins.jetbrains.com/plugin/8527-google-java-format) * [Google Java Format](https://plugins.jetbrains.com/plugin/8527-google-java-format)

View File

@ -1,5 +1,7 @@
package datadog.trace.api; package datadog.trace.api;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -51,6 +53,7 @@ public class Config {
public static final String TRACE_ANNOTATIONS = "trace.annotations"; public static final String TRACE_ANNOTATIONS = "trace.annotations";
public static final String TRACE_METHODS = "trace.methods"; public static final String TRACE_METHODS = "trace.methods";
public static final String TRACE_CLASSES_EXCLUDE = "trace.classes.exclude"; public static final String TRACE_CLASSES_EXCLUDE = "trace.classes.exclude";
public static final String TRACE_REPORT_HOSTNAME = "trace.report-hostname";
public static final String HEADER_TAGS = "trace.header.tags"; public static final String HEADER_TAGS = "trace.header.tags";
public static final String HTTP_SERVER_ERROR_STATUSES = "http.server.error.statuses"; public static final String HTTP_SERVER_ERROR_STATUSES = "http.server.error.statuses";
public static final String HTTP_CLIENT_ERROR_STATUSES = "http.client.error.statuses"; public static final String HTTP_CLIENT_ERROR_STATUSES = "http.client.error.statuses";
@ -105,11 +108,16 @@ public class Config {
private static final String SPLIT_BY_SPACE_OR_COMMA_REGEX = "[,\\s]+"; private static final String SPLIT_BY_SPACE_OR_COMMA_REGEX = "[,\\s]+";
private static final boolean DEFAULT_TRACE_REPORT_HOSTNAME = false;
public enum PropagationStyle { public enum PropagationStyle {
DATADOG, DATADOG,
B3 B3
} }
/** A tag intended for internal use only, hence not added to the public api DDTags class. */
private static final String INTERNAL_HOST_NAME = "_dd.hostname";
/** /**
* this is a random UUID that gets generated on JVM start up and is attached to every root span * this is a random UUID that gets generated on JVM start up and is attached to every root span
* and every JMX metric that is sent out. * and every JMX metric that is sent out.
@ -147,6 +155,8 @@ public class Config {
@Getter private final boolean logsInjectionEnabled; @Getter private final boolean logsInjectionEnabled;
@Getter private final boolean reportHostName;
// Read order: System Properties -> Env Variables, [-> default value] // Read order: System Properties -> Env Variables, [-> default value]
// Visible for testing // Visible for testing
Config() { Config() {
@ -221,6 +231,9 @@ public class Config {
logsInjectionEnabled = logsInjectionEnabled =
getBooleanSettingFromEnvironment(LOGS_INJECTION_ENABLED, DEFAULT_LOGS_INJECTION_ENABLED); getBooleanSettingFromEnvironment(LOGS_INJECTION_ENABLED, DEFAULT_LOGS_INJECTION_ENABLED);
reportHostName =
getBooleanSettingFromEnvironment(TRACE_REPORT_HOSTNAME, DEFAULT_TRACE_REPORT_HOSTNAME);
log.debug("New instance: {}", this); log.debug("New instance: {}", this);
} }
@ -301,9 +314,24 @@ public class Config {
logsInjectionEnabled = logsInjectionEnabled =
getBooleanSettingFromEnvironment(LOGS_INJECTION_ENABLED, DEFAULT_LOGS_INJECTION_ENABLED); getBooleanSettingFromEnvironment(LOGS_INJECTION_ENABLED, DEFAULT_LOGS_INJECTION_ENABLED);
reportHostName =
getPropertyBooleanValue(properties, TRACE_REPORT_HOSTNAME, parent.reportHostName);
log.debug("New instance: {}", this); log.debug("New instance: {}", this);
} }
/** @return A map of tags to be applied only to the local application root span. */
public Map<String, String> getLocalRootSpanTags() {
final Map<String, String> runtimeTags = getRuntimeTags();
final Map<String, String> result =
newHashMap(reportHostName ? (runtimeTags.size() + 1) : runtimeTags.size());
result.putAll(runtimeTags);
if (reportHostName) {
result.put(INTERNAL_HOST_NAME, getHostname());
}
return Collections.unmodifiableMap(result);
}
public Map<String, String> getMergedSpanTags() { public Map<String, String> getMergedSpanTags() {
// DO not include runtimeId into span tags: we only want that added to the root span // DO not include runtimeId into span tags: we only want that added to the root span
final Map<String, String> result = newHashMap(globalTags.size() + spanTags.size()); final Map<String, String> result = newHashMap(globalTags.size() + spanTags.size());
@ -336,7 +364,7 @@ public class Config {
* *
* @return A map of tag-name -> tag-value * @return A map of tag-name -> tag-value
*/ */
public Map<String, String> getRuntimeTags() { private Map<String, String> getRuntimeTags() {
final Map<String, String> result = newHashMap(2); final Map<String, String> result = newHashMap(2);
result.put(RUNTIME_ID_TAG, runtimeId); result.put(RUNTIME_ID_TAG, runtimeId);
result.put(LANGUAGE_TAG_KEY, LANGUAGE_TAG_VALUE); result.put(LANGUAGE_TAG_KEY, LANGUAGE_TAG_VALUE);
@ -636,6 +664,20 @@ public class Config {
return Collections.unmodifiableSet(result); return Collections.unmodifiableSet(result);
} }
/**
* Returns the detected hostname. This operation is time consuming so if the usage changes and
* this method will be called several times then we should implement some sort of caching.
*/
private String getHostname() {
try {
return InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
// If we are not able to detect the hostname we do not throw an exception.
}
return null;
}
// This has to be placed after all other static fields to give them a chance to initialize // This has to be placed after all other static fields to give them a chance to initialize
private static final Config INSTANCE = new Config(); private static final Config INSTANCE = new Config();

View File

@ -50,5 +50,16 @@ public interface MutableSpan {
MutableSpan setError(boolean value); MutableSpan setError(boolean value);
/** @deprecated Use {@link #getLocalRootSpan()} instead. */
@Deprecated
MutableSpan getRootSpan(); MutableSpan getRootSpan();
/**
* Returns the root span for current the trace fragment. In the context of distributed tracing
* this method returns the root span only for the fragment generated by the currently traced
* application.
*
* @return The root span for the current trace fragment.
*/
MutableSpan getLocalRootSpan();
} }

View File

@ -35,6 +35,7 @@ import static datadog.trace.api.Config.SERVICE_MAPPING
import static datadog.trace.api.Config.SERVICE_NAME import static datadog.trace.api.Config.SERVICE_NAME
import static datadog.trace.api.Config.SPAN_TAGS import static datadog.trace.api.Config.SPAN_TAGS
import static datadog.trace.api.Config.TRACE_AGENT_PORT import static datadog.trace.api.Config.TRACE_AGENT_PORT
import static datadog.trace.api.Config.TRACE_REPORT_HOSTNAME
import static datadog.trace.api.Config.TRACE_ENABLED import static datadog.trace.api.Config.TRACE_ENABLED
import static datadog.trace.api.Config.TRACE_RESOLVER_ENABLED import static datadog.trace.api.Config.TRACE_RESOLVER_ENABLED
import static datadog.trace.api.Config.WRITER_TYPE import static datadog.trace.api.Config.WRITER_TYPE
@ -56,6 +57,7 @@ class ConfigTest extends Specification {
private static final DD_JMXFETCH_METRICS_CONFIGS_ENV = "DD_JMXFETCH_METRICS_CONFIGS" private static final DD_JMXFETCH_METRICS_CONFIGS_ENV = "DD_JMXFETCH_METRICS_CONFIGS"
private static final DD_TRACE_AGENT_PORT_ENV = "DD_TRACE_AGENT_PORT" private static final DD_TRACE_AGENT_PORT_ENV = "DD_TRACE_AGENT_PORT"
private static final DD_AGENT_PORT_LEGACY_ENV = "DD_AGENT_PORT" private static final DD_AGENT_PORT_LEGACY_ENV = "DD_AGENT_PORT"
private static final DD_TRACE_REPORT_HOSTNAME = "DD_TRACE_REPORT_HOSTNAME"
def "verify defaults"() { def "verify defaults"() {
when: when:
@ -78,6 +80,7 @@ class ConfigTest extends Specification {
config.httpClientErrorStatuses == (400..499).toSet() config.httpClientErrorStatuses == (400..499).toSet()
config.httpClientSplitByDomain == false config.httpClientSplitByDomain == false
config.partialFlushMinSpans == 1000 config.partialFlushMinSpans == 1000
config.reportHostName == false
config.runtimeContextFieldInjection == true config.runtimeContextFieldInjection == true
config.propagationStylesToExtract.toList() == [Config.PropagationStyle.DATADOG] config.propagationStylesToExtract.toList() == [Config.PropagationStyle.DATADOG]
config.propagationStylesToInject.toList() == [Config.PropagationStyle.DATADOG] config.propagationStylesToInject.toList() == [Config.PropagationStyle.DATADOG]
@ -118,6 +121,7 @@ class ConfigTest extends Specification {
prop.setProperty(HTTP_CLIENT_ERROR_STATUSES, "111") prop.setProperty(HTTP_CLIENT_ERROR_STATUSES, "111")
prop.setProperty(HTTP_CLIENT_HOST_SPLIT_BY_DOMAIN, "true") prop.setProperty(HTTP_CLIENT_HOST_SPLIT_BY_DOMAIN, "true")
prop.setProperty(PARTIAL_FLUSH_MIN_SPANS, "15") prop.setProperty(PARTIAL_FLUSH_MIN_SPANS, "15")
prop.setProperty(TRACE_REPORT_HOSTNAME, "true")
prop.setProperty(RUNTIME_CONTEXT_FIELD_INJECTION, "false") prop.setProperty(RUNTIME_CONTEXT_FIELD_INJECTION, "false")
prop.setProperty(PROPAGATION_STYLE_EXTRACT, "Datadog, B3") prop.setProperty(PROPAGATION_STYLE_EXTRACT, "Datadog, B3")
prop.setProperty(PROPAGATION_STYLE_INJECT, "B3, Datadog") prop.setProperty(PROPAGATION_STYLE_INJECT, "B3, Datadog")
@ -148,6 +152,7 @@ class ConfigTest extends Specification {
config.httpClientErrorStatuses == (111..111).toSet() config.httpClientErrorStatuses == (111..111).toSet()
config.httpClientSplitByDomain == true config.httpClientSplitByDomain == true
config.partialFlushMinSpans == 15 config.partialFlushMinSpans == 15
config.reportHostName == true
config.runtimeContextFieldInjection == false config.runtimeContextFieldInjection == false
config.propagationStylesToExtract.toList() == [Config.PropagationStyle.DATADOG, Config.PropagationStyle.B3] config.propagationStylesToExtract.toList() == [Config.PropagationStyle.DATADOG, Config.PropagationStyle.B3]
config.propagationStylesToInject.toList() == [Config.PropagationStyle.B3, Config.PropagationStyle.DATADOG] config.propagationStylesToInject.toList() == [Config.PropagationStyle.B3, Config.PropagationStyle.DATADOG]
@ -179,6 +184,7 @@ class ConfigTest extends Specification {
System.setProperty(PREFIX + HTTP_CLIENT_ERROR_STATUSES, "111") System.setProperty(PREFIX + HTTP_CLIENT_ERROR_STATUSES, "111")
System.setProperty(PREFIX + HTTP_CLIENT_HOST_SPLIT_BY_DOMAIN, "true") System.setProperty(PREFIX + HTTP_CLIENT_HOST_SPLIT_BY_DOMAIN, "true")
System.setProperty(PREFIX + PARTIAL_FLUSH_MIN_SPANS, "25") System.setProperty(PREFIX + PARTIAL_FLUSH_MIN_SPANS, "25")
System.setProperty(PREFIX + TRACE_REPORT_HOSTNAME, "true")
System.setProperty(PREFIX + RUNTIME_CONTEXT_FIELD_INJECTION, "false") System.setProperty(PREFIX + RUNTIME_CONTEXT_FIELD_INJECTION, "false")
System.setProperty(PREFIX + PROPAGATION_STYLE_EXTRACT, "Datadog, B3") System.setProperty(PREFIX + PROPAGATION_STYLE_EXTRACT, "Datadog, B3")
System.setProperty(PREFIX + PROPAGATION_STYLE_INJECT, "B3, Datadog") System.setProperty(PREFIX + PROPAGATION_STYLE_INJECT, "B3, Datadog")
@ -209,6 +215,7 @@ class ConfigTest extends Specification {
config.httpClientErrorStatuses == (111..111).toSet() config.httpClientErrorStatuses == (111..111).toSet()
config.httpClientSplitByDomain == true config.httpClientSplitByDomain == true
config.partialFlushMinSpans == 25 config.partialFlushMinSpans == 25
config.reportHostName == true
config.runtimeContextFieldInjection == false config.runtimeContextFieldInjection == false
config.propagationStylesToExtract.toList() == [Config.PropagationStyle.DATADOG, Config.PropagationStyle.B3] config.propagationStylesToExtract.toList() == [Config.PropagationStyle.DATADOG, Config.PropagationStyle.B3]
config.propagationStylesToInject.toList() == [Config.PropagationStyle.B3, Config.PropagationStyle.DATADOG] config.propagationStylesToInject.toList() == [Config.PropagationStyle.B3, Config.PropagationStyle.DATADOG]
@ -228,6 +235,7 @@ class ConfigTest extends Specification {
environmentVariables.set(DD_PROPAGATION_STYLE_EXTRACT, "B3 Datadog") environmentVariables.set(DD_PROPAGATION_STYLE_EXTRACT, "B3 Datadog")
environmentVariables.set(DD_PROPAGATION_STYLE_INJECT, "Datadog B3") environmentVariables.set(DD_PROPAGATION_STYLE_INJECT, "Datadog B3")
environmentVariables.set(DD_JMXFETCH_METRICS_CONFIGS_ENV, "some/file") environmentVariables.set(DD_JMXFETCH_METRICS_CONFIGS_ENV, "some/file")
environmentVariables.set(DD_TRACE_REPORT_HOSTNAME, "true")
when: when:
def config = new Config() def config = new Config()
@ -239,6 +247,7 @@ class ConfigTest extends Specification {
config.propagationStylesToExtract.toList() == [Config.PropagationStyle.B3, Config.PropagationStyle.DATADOG] config.propagationStylesToExtract.toList() == [Config.PropagationStyle.B3, Config.PropagationStyle.DATADOG]
config.propagationStylesToInject.toList() == [Config.PropagationStyle.DATADOG, Config.PropagationStyle.B3] config.propagationStylesToInject.toList() == [Config.PropagationStyle.DATADOG, Config.PropagationStyle.B3]
config.jmxFetchMetricsConfigs == ["some/file"] config.jmxFetchMetricsConfigs == ["some/file"]
config.reportHostName == true
} }
def "sys props override env vars"() { def "sys props override env vars"() {
@ -649,4 +658,27 @@ class ConfigTest extends Specification {
listString | list listString | list
"" | [] "" | []
} }
def "verify hostname not added to root span tags by default"() {
setup:
Properties properties = new Properties()
when:
def config = Config.get(properties)
then:
!config.localRootSpanTags.containsKey('_dd.hostname')
}
def "verify configuration to add hostname to root span tags"() {
setup:
Properties properties = new Properties()
properties.setProperty(TRACE_REPORT_HOSTNAME, 'true')
when:
def config = Config.get(properties)
then:
config.localRootSpanTags.get('_dd.hostname') == InetAddress.localHost.hostName
}
} }

View File

@ -110,8 +110,16 @@ public class DDSpan implements Span, MutableSpan {
finishAndAddToTrace(TimeUnit.MICROSECONDS.toNanos(stoptimeMicros - startTimeMicro)); finishAndAddToTrace(TimeUnit.MICROSECONDS.toNanos(stoptimeMicros - startTimeMicro));
} }
@Override
public DDSpan setError(final boolean error) {
context.setErrorFlag(true);
return this;
}
/** /**
* Check if the span is the root parent. It means that the traceId is the same as the spanId * Check if the span is the root parent. It means that the traceId is the same as the spanId. In
* the context of distributed tracing this will return true if an only if this is the application
* initializing the trace.
* *
* @return true if root, false otherwise * @return true if root, false otherwise
*/ */
@ -121,13 +129,15 @@ public class DDSpan implements Span, MutableSpan {
} }
@Override @Override
public DDSpan setError(final boolean error) { @Deprecated
context.setErrorFlag(true); @JsonIgnore
return this; public MutableSpan getRootSpan() {
return getLocalRootSpan();
} }
@Override @Override
public MutableSpan getRootSpan() { @JsonIgnore
public MutableSpan getLocalRootSpan() {
return context().getTrace().getRootSpan(); return context().getTrace().getRootSpan();
} }

View File

@ -56,8 +56,8 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
/** Scope manager is in charge of managing the scopes from which spans are created */ /** Scope manager is in charge of managing the scopes from which spans are created */
final ContextualScopeManager scopeManager = new ContextualScopeManager(); final ContextualScopeManager scopeManager = new ContextualScopeManager();
/** Tags required to link apm traces to runtime metrics */ /** A set of tags that are added only to the application's root span */
final Map<String, String> runtimeTags; private final Map<String, String> localRootSpanTags;
/** A set of tags that are added to every span */ /** A set of tags that are added to every span */
private final Map<String, String> defaultSpanTags; private final Map<String, String> defaultSpanTags;
/** A configured mapping of service names to update with new values */ /** A configured mapping of service names to update with new values */
@ -107,7 +107,7 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
// This constructor is already used in the wild, so we have to keep it inside this API for now. // This constructor is already used in the wild, so we have to keep it inside this API for now.
public DDTracer(final String serviceName, final Writer writer, final Sampler sampler) { public DDTracer(final String serviceName, final Writer writer, final Sampler sampler) {
this(serviceName, writer, sampler, Config.get().getRuntimeTags()); this(serviceName, writer, sampler, Config.get().getLocalRootSpanTags());
} }
private DDTracer(final String serviceName, final Config config) { private DDTracer(final String serviceName, final Config config) {
@ -115,7 +115,7 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
serviceName, serviceName,
Writer.Builder.forConfig(config), Writer.Builder.forConfig(config),
Sampler.Builder.forConfig(config), Sampler.Builder.forConfig(config),
config.getRuntimeTags(), config.getLocalRootSpanTags(),
config.getMergedSpanTags(), config.getMergedSpanTags(),
config.getServiceMapping(), config.getServiceMapping(),
config.getHeaderTags(), config.getHeaderTags(),
@ -149,7 +149,7 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
config.getServiceName(), config.getServiceName(),
writer, writer,
Sampler.Builder.forConfig(config), Sampler.Builder.forConfig(config),
config.getRuntimeTags(), config.getLocalRootSpanTags(),
config.getMergedSpanTags(), config.getMergedSpanTags(),
config.getServiceMapping(), config.getServiceMapping(),
config.getHeaderTags(), config.getHeaderTags(),
@ -165,6 +165,7 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
final Writer writer, final Writer writer,
final Sampler sampler, final Sampler sampler,
final String runtimeId, final String runtimeId,
final Map<String, String> localRootSpanTags,
final Map<String, String> defaultSpanTags, final Map<String, String> defaultSpanTags,
final Map<String, String> serviceNameMappings, final Map<String, String> serviceNameMappings,
final Map<String, String> taggedHeaders) { final Map<String, String> taggedHeaders) {
@ -172,7 +173,7 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
serviceName, serviceName,
writer, writer,
sampler, sampler,
customRuntimeTags(runtimeId), customRuntimeTags(runtimeId, localRootSpanTags),
defaultSpanTags, defaultSpanTags,
serviceNameMappings, serviceNameMappings,
taggedHeaders, taggedHeaders,
@ -187,7 +188,7 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
final String serviceName, final String serviceName,
final Writer writer, final Writer writer,
final Sampler sampler, final Sampler sampler,
final Map<String, String> runtimeTags, final Map<String, String> localRootSpanTags,
final Map<String, String> defaultSpanTags, final Map<String, String> defaultSpanTags,
final Map<String, String> serviceNameMappings, final Map<String, String> serviceNameMappings,
final Map<String, String> taggedHeaders) { final Map<String, String> taggedHeaders) {
@ -195,7 +196,7 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
serviceName, serviceName,
writer, writer,
sampler, sampler,
runtimeTags, localRootSpanTags,
defaultSpanTags, defaultSpanTags,
serviceNameMappings, serviceNameMappings,
taggedHeaders, taggedHeaders,
@ -206,12 +207,12 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
final String serviceName, final String serviceName,
final Writer writer, final Writer writer,
final Sampler sampler, final Sampler sampler,
final Map<String, String> runtimeTags, final Map<String, String> localRootSpanTags,
final Map<String, String> defaultSpanTags, final Map<String, String> defaultSpanTags,
final Map<String, String> serviceNameMappings, final Map<String, String> serviceNameMappings,
final Map<String, String> taggedHeaders, final Map<String, String> taggedHeaders,
final int partialFlushMinSpans) { final int partialFlushMinSpans) {
assert runtimeTags != null; assert localRootSpanTags != null;
assert defaultSpanTags != null; assert defaultSpanTags != null;
assert serviceNameMappings != null; assert serviceNameMappings != null;
assert taggedHeaders != null; assert taggedHeaders != null;
@ -220,8 +221,8 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
this.writer = writer; this.writer = writer;
this.writer.start(); this.writer.start();
this.sampler = sampler; this.sampler = sampler;
this.localRootSpanTags = localRootSpanTags;
this.defaultSpanTags = defaultSpanTags; this.defaultSpanTags = defaultSpanTags;
this.runtimeTags = runtimeTags;
this.serviceNameMappings = serviceNameMappings; this.serviceNameMappings = serviceNameMappings;
this.partialFlushMinSpans = partialFlushMinSpans; this.partialFlushMinSpans = partialFlushMinSpans;
@ -439,9 +440,9 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
} }
@Deprecated @Deprecated
private static Map<String, String> customRuntimeTags(final String runtimeId) { private static Map<String, String> customRuntimeTags(
final Map<String, String> runtimeTags = new HashMap<>(); final String runtimeId, Map<String, String> applicationRootSpanTags) {
runtimeTags.putAll(Config.get().getRuntimeTags()); final Map<String, String> runtimeTags = new HashMap<>(applicationRootSpanTags);
runtimeTags.put(Config.RUNTIME_ID_TAG, runtimeId); runtimeTags.put(Config.RUNTIME_ID_TAG, runtimeId);
return Collections.unmodifiableMap(runtimeTags); return Collections.unmodifiableMap(runtimeTags);
} }
@ -623,7 +624,9 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
} }
} }
// Propagate internal trace // Propagate internal trace.
// Note: if we are not in the context of distributed tracing and we are starting the first
// root span, parentContext will be null at this point.
if (parentContext instanceof DDSpanContext) { if (parentContext instanceof DDSpanContext) {
final DDSpanContext ddsc = (DDSpanContext) parentContext; final DDSpanContext ddsc = (DDSpanContext) parentContext;
traceId = ddsc.getTraceId(); traceId = ddsc.getTraceId();
@ -660,10 +663,7 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
origin = null; origin = null;
} }
// add runtime tags to the root span tags.putAll(localRootSpanTags);
for (final Map.Entry<String, String> runtimeTag : runtimeTags.entrySet()) {
tags.put(runtimeTag.getKey(), runtimeTag.getValue());
}
parentTrace = new PendingTrace(DDTracer.this, traceId, serviceNameMappings); parentTrace = new PendingTrace(DDTracer.this, traceId, serviceNameMappings);
} }

View File

@ -5,6 +5,7 @@ import datadog.opentracing.propagation.TagContext
import datadog.trace.api.sampling.PrioritySampling import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.sampling.RateByServiceSampler import datadog.trace.common.sampling.RateByServiceSampler
import datadog.trace.common.writer.ListWriter import datadog.trace.common.writer.ListWriter
import io.opentracing.SpanContext
import spock.lang.Shared import spock.lang.Shared
import spock.lang.Specification import spock.lang.Specification
@ -207,18 +208,45 @@ class DDSpanTest extends Specification {
new ExtractedContext("1", "2", 0, "some-origin", [:], [:]) | _ new ExtractedContext("1", "2", 0, "some-origin", [:], [:]) | _
} }
def "getRootSpan returns the root span"() { def "isRootSpan() in and not in the context of distributed tracing"() {
setup: setup:
def root = tracer.buildSpan("root").start() def root = tracer.buildSpan("root").asChildOf((SpanContext)extractedContext).start()
def child = tracer.buildSpan("child").asChildOf(root).start() def child = tracer.buildSpan("child").asChildOf(root).start()
expect: expect:
root.getRootSpan() == root root.isRootSpan() == isTraceRootSpan
child.getRootSpan() == root !child.isRootSpan()
cleanup: cleanup:
child.finish() child.finish()
root.finish() root.finish()
where:
extractedContext | isTraceRootSpan
null | true
new ExtractedContext("123", "456", 1, "789", [:], [:]) | false
}
def "getApplicationRootSpan() in and not in the context of distributed tracing"() {
setup:
def root = tracer.buildSpan("root").asChildOf((SpanContext)extractedContext).start()
def child = tracer.buildSpan("child").asChildOf(root).start()
expect:
root.localRootSpan == root
child.localRootSpan == root
// Checking for backward compatibility method names
root.rootSpan == root
child.rootSpan == root
cleanup:
child.finish()
root.finish()
where:
extractedContext | isTraceRootSpan
null | true
new ExtractedContext("123", "456", 1, "789", [:], [:]) | false
} }
def "setting forced tracing via tag"() { def "setting forced tracing via tag"() {

View File

@ -49,6 +49,7 @@ class SpanDecoratorTest extends Specification {
new AllSampler(), new AllSampler(),
"some-runtime-id", "some-runtime-id",
emptyMap(), emptyMap(),
emptyMap(),
mapping, mapping,
emptyMap() emptyMap()
) )
@ -80,6 +81,7 @@ class SpanDecoratorTest extends Specification {
new AllSampler(), new AllSampler(),
"some-runtime-id", "some-runtime-id",
emptyMap(), emptyMap(),
emptyMap(),
mapping, mapping,
emptyMap() emptyMap()
) )
@ -126,6 +128,7 @@ class SpanDecoratorTest extends Specification {
new AllSampler(), new AllSampler(),
"some-runtime-id", "some-runtime-id",
emptyMap(), emptyMap(),
emptyMap(),
mapping, mapping,
emptyMap() emptyMap()
) )

View File

@ -31,7 +31,7 @@ class DDTracerTest extends Specification {
// assert that a trace agent isn't running locally as that messes up the test. // assert that a trace agent isn't running locally as that messes up the test.
try { try {
(new Socket("localhost", 8126)).close() (new Socket("localhost", 8126)).close()
throw new IllegalStateException("Trace Agent unexpectedly running locally.") throw new IllegalStateException("An agent is already running locally on port 8126. Please stop it if you want to run tests locally.")
} catch (final ConnectException ioe) { } catch (final ConnectException ioe) {
// trace agent is not running locally. // trace agent is not running locally.
} }
@ -126,8 +126,8 @@ class DDTracerTest extends Specification {
tracer.serviceName == DEFAULT_SERVICE_NAME tracer.serviceName == DEFAULT_SERVICE_NAME
tracer.sampler == sampler tracer.sampler == sampler
tracer.writer == writer tracer.writer == writer
tracer.runtimeTags[Config.RUNTIME_ID_TAG].size() > 0 // not null or empty tracer.localRootSpanTags[Config.RUNTIME_ID_TAG].size() > 0 // not null or empty
tracer.runtimeTags[Config.LANGUAGE_TAG_KEY] == Config.LANGUAGE_TAG_VALUE tracer.localRootSpanTags[Config.LANGUAGE_TAG_KEY] == Config.LANGUAGE_TAG_VALUE
} }
def "Shares TraceCount with DDApi with #key = #value"() { def "Shares TraceCount with DDApi with #key = #value"() {
@ -144,4 +144,19 @@ class DDTracerTest extends Specification {
PRIORITY_SAMPLING | "true" PRIORITY_SAMPLING | "true"
PRIORITY_SAMPLING | "false" PRIORITY_SAMPLING | "false"
} }
def "root tags are applied only to root spans"() {
setup:
def tracer = new DDTracer('my_service', new ListWriter(), new AllSampler(), '', ['only_root': 'value'], [:], [:], [:])
def root = tracer.buildSpan('my_root').start()
def child = tracer.buildSpan('my_child').asChildOf(root).start()
expect:
root.context().tags.containsKey('only_root')
!child.context().tags.containsKey('only_root')
cleanup:
child.finish()
root.finish()
}
} }