Rebrand priority sampling while being BC with legacy approach to set it
MODIFY
dd-trace-api/src/main/java/datadog/trace/api/interceptor/MutableSpan.java
dd-trace-api/src/main/java/datadog/trace/api/interceptor/MutableSpan.java
@@ -24,6 +24,15 @@ public interface MutableSpan {
Integer getSamplingPriority();
+ /**
+ * @deprecated Use {@link MutableSpan#setTag(String, boolean)} instead using either tag names
+ * {@link datadog.trace.api.sampling.ForcedTracing#manual_KEEP} or
+ * {@link datadog.trace.api.sampling.ForcedTracing#manual_DROP}.
+ *
+ * @param newPriority
+ * @return
+ */
+ @Deprecated
MutableSpan setSamplingPriority(final int newPriority);
String getSpanType();

ADD
dd-trace-api/src/main/java/datadog/trace/api/sampling/ForcedTracing.java
+package datadog.trace.api.sampling;
+
+/**
+ * Class exposing tag names to mark a span to be dropped or kept by the sampler based on user intent.
+ */
+final public class ForcedTracing {
+
+ /**
+ * The user has decided to drop the trace.
+ */
+ public static final String manual_DROP = "manual.drop";
+
+ /**
+ * The user has decided to keep the trace.
+ */
+ public static final String manual_KEEP = "manual.keep";
+
+ private ForcedTracing() {}
+}

MODIFY
dd-trace-ot/src/main/java/datadog/opentracing/DDSpanContext.java
dd-trace-ot/src/main/java/datadog/opentracing/DDSpanContext.java
@@ -3,6 +3,7 @@ package datadog.opentracing;
import com.fasterxml.jackson.annotation.JsonIgnore;
import datadog.opentracing.decorators.AbstractDecorator;
import datadog.trace.api.DDTags;
+import datadog.trace.api.sampling.ForcedTracing;
import datadog.trace.api.sampling.PrioritySampling;
import java.util.Collections;
import java.util.List;
@@ -202,6 +203,13 @@ public class DDSpanContext implements io.opentracing.SpanContext {
} else {
setMetric(PRIORITY_SAMPLING_KEY, newPriority);
log.debug("Set sampling priority to {}", getMetrics().get(PRIORITY_SAMPLING_KEY));
+
+ // Keep in sync forced tracing tags with sampling priority
+ if (newPriority == PrioritySampling.USER_KEEP) {
+ tags.put(ForcedTracing.manual_KEEP, true);
+ } else if (newPriority == PrioritySampling.USER_DROP) {
+ tags.put(ForcedTracing.manual_DROP, true);
+ }
}
}
}
@@ -313,6 +321,15 @@ public class DDSpanContext implements io.opentracing.SpanContext {
return;
}
+ // For priority sampling we use tags ForcedTracing#manual_DROP and ForcedTracing#manual_KEEP as vectors to set the
+ // respective priority sample values. A decorator is not a viable option to achieve this as handles primarily tags
+ // and does not expose an API to perform more complex operations. We may want to revisit this functionality, but for
+ // now we do it manually here.
+ if (tag.equals(ForcedTracing.manual_KEEP) || tag.equals(ForcedTracing.manual_DROP)) {
+ this.processForcedTracingTag(tag, value);
+ return;
+ }
+
boolean addTag = true;
// Call decorators
@@ -335,6 +352,24 @@ public class DDSpanContext implements io.opentracing.SpanContext {
}
}
+ /**
+ * Sets priority sampling based on the forced tracing tag provided by the user.
+ *
+ * @param tag
+ * @param value
+ */
+ private void processForcedTracingTag(final String tag, Object value) {
+ if (!(value instanceof Boolean)) {
+ return;
+ }
+
+ if (tag.equals(ForcedTracing.manual_KEEP) && (boolean)value) {
+ this.setSamplingPriority(PrioritySampling.USER_KEEP);
+ } else if (tag.equals(ForcedTracing.manual_DROP) && (boolean)value) {
+ this.setSamplingPriority(PrioritySampling.USER_DROP);
+ }
+ }
+
public synchronized Map<String, Object> getTags() {
return Collections.unmodifiableMap(tags);
}

MODIFY
dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanTest.groovy
dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanTest.groovy
@@ -5,6 +5,7 @@ import datadog.opentracing.propagation.TagContext
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.common.sampling.RateByServiceSampler
import datadog.trace.common.writer.ListWriter
+import spock.lang.Shared
import spock.lang.Specification
import java.util.concurrent.TimeUnit
@@ -15,6 +16,9 @@ class DDSpanTest extends Specification {
def writer = new ListWriter()
def tracer = new DDTracer(DEFAULT_SERVICE_NAME, writer, new RateByServiceSampler(), [:])
+ @Shared
+ def defaultSamplingPriority = PrioritySampling.SAMPLER_KEEP
+
def "getters and setters"() {
setup:
final DDSpanContext context =
@@ -216,4 +220,62 @@ class DDSpanTest extends Specification {
child.finish()
root.finish()
}
+
+ def "setting forced tracing via tag"() {
+
+ setup:
+ def span = tracer.buildSpan("root").start()
+ if (tagName) span.setTag(tagName, tagValue)
+
+ expect:
+ // Tag and sampling priority kept in sync
+ span.getSamplingPriority() == expectedPriority
+ span.getTags()[tagName] == true
+
+ cleanup:
+ span.finish()
+
+ where:
+ tagName | tagValue | expectedPriority
+ 'manual.drop' | true | PrioritySampling.USER_DROP
+ 'manual.keep' | true | PrioritySampling.USER_KEEP
+ }
+
+ def "not setting forced tracing via tag or setting it wrong value not causing exception"() {
+
+ setup:
+ def span = tracer.buildSpan("root").start()
+ if (tagName) span.setTag(tagName, tagValue)
+
+ expect:
+ span.getSamplingPriority() == defaultSamplingPriority
+
+ cleanup:
+ span.finish()
+
+ where:
+ tagName | tagValue
+ // When no tag is set default to
+ null | null
+ // Setting to not known value
+ 'manual.drop' | false
+ 'manual.keep' | false
+ 'manual.drop' | 1
+ 'manual.keep' | 1
+ }
+
+ def "setting sampling priority via deprecated method keep tag in sync"() {
+
+ setup:
+ def span = tracer.buildSpan("root").start()
+ span.samplingPriority = PrioritySampling.USER_KEEP
+
+ expect:
+ // Tag and sampling priority kept in sync
+ span.getSamplingPriority() == PrioritySampling.USER_KEEP
+ span.getTags()['manual.keep'] == true
+
+ cleanup:
+ span.finish()
+ }
}

Rebrand priority sampling while being BC with legacy approach to set it