Add tests for rules
MODIFY
dd-trace-ot/src/test/groovy/datadog/trace/api/sampling/RateByServiceSamplerTest.groovy
dd-trace-ot/src/test/groovy/datadog/trace/api/sampling/RateByServiceSamplerTest.groovy
@@ -38,7 +38,7 @@ class RateByServiceSamplerTest extends DDSpecification {
String response = '{"rate_by_service": {"service:spock,env:test":0.0}}'
serviceSampler.onResponse("traces", serializer.readTree(response))
DDSpan span1 = SpanFactory.newSpanOf("foo", "bar")
- serviceSampler.initializeSamplingPriority(span1)
+ serviceSampler.setSamplingPriority(span1)
then:
span1.getSamplingPriority() == PrioritySampling.SAMPLER_KEEP
serviceSampler.sample(span1)
@@ -47,7 +47,7 @@ class RateByServiceSamplerTest extends DDSpecification {
response = '{"rate_by_service": {"service:spock,env:test":1.0}}'
serviceSampler.onResponse("traces", serializer.readTree(response))
DDSpan span2 = SpanFactory.newSpanOf("spock", "test")
- serviceSampler.initializeSamplingPriority(span2)
+ serviceSampler.setSamplingPriority(span2)
then:
span2.getSamplingPriority() == PrioritySampling.SAMPLER_KEEP
serviceSampler.sample(span2)
@@ -61,7 +61,7 @@ class RateByServiceSamplerTest extends DDSpecification {
serviceSampler.onResponse("traces", serializer.readTree(response))
DDSpan span = SpanFactory.newSpanOf("foo", "bar")
- serviceSampler.initializeSamplingPriority(span)
+ serviceSampler.setSamplingPriority(span)
expect:
// sets correctly on root span
span.getSamplingPriority() == PrioritySampling.SAMPLER_KEEP

ADD
dd-trace-ot/src/test/groovy/datadog/trace/api/sampling/RuleBasedSamplingTest.groovy
+package datadog.trace.api.sampling
+
+import datadog.opentracing.DDSpan
+import datadog.opentracing.SpanFactory
+import datadog.trace.common.sampling.PrioritySampler
+import datadog.trace.common.sampling.RateByServiceSampler
+import datadog.trace.common.sampling.RuleBasedSampler
+import datadog.trace.common.sampling.Sampler
+import datadog.trace.util.test.DDSpecification
+
+import static datadog.trace.api.Config.TRACE_SAMPLING_DEFAULT_RATE
+import static datadog.trace.api.Config.TRACE_SAMPLING_OPERATION_RULES
+import static datadog.trace.api.Config.TRACE_SAMPLING_RATE_LIMIT
+import static datadog.trace.api.Config.TRACE_SAMPLING_SERVICE_RULES
+import static datadog.trace.api.sampling.PrioritySampling.SAMPLER_DROP
+import static datadog.trace.api.sampling.PrioritySampling.SAMPLER_KEEP
+
+class RuleBasedSamplingTest extends DDSpecification {
+ def "Rule Based Sampler is not created when properties not set"() {
+ when:
+ Sampler sampler = Sampler.Builder.forConfig(new Properties())
+
+ then:
+ !(sampler instanceof RuleBasedSampler)
+ }
+
+ def "Rule Based Sampler is not created when just rate limit set"() {
+ when:
+ Properties properties = new Properties()
+ properties.setProperty(TRACE_SAMPLING_RATE_LIMIT, "50")
+ Sampler sampler = Sampler.Builder.forConfig(properties)
+
+ then:
+ !(sampler instanceof RuleBasedSampler)
+ }
+
+ def "sampling config combinations"() {
+ given:
+ Properties properties = new Properties()
+ if (serviceRules != null) {
+ properties.setProperty(TRACE_SAMPLING_SERVICE_RULES, serviceRules)
+ }
+
+ if (operationRules != null) {
+ properties.setProperty(TRACE_SAMPLING_OPERATION_RULES, operationRules)
+ }
+
+ if (defaultRate != null) {
+ properties.setProperty(TRACE_SAMPLING_DEFAULT_RATE, defaultRate)
+ }
+
+ if (rateLimit != null) {
+ properties.setProperty(TRACE_SAMPLING_RATE_LIMIT, rateLimit)
+ }
+
+ when:
+ Sampler sampler = Sampler.Builder.forConfig(properties)
+
+ then:
+ sampler instanceof PrioritySampler
+
+ when:
+ DDSpan span = SpanFactory.newSpanOf("service", "bar")
+ span.setOperationName("operation")
+ ((PrioritySampler) sampler).setSamplingPriority(span)
+
+ then:
+ span.getMetrics().get(RuleBasedSampler.SAMPLING_RULE_RATE) == expectedRuleRate
+ span.getMetrics().get(RuleBasedSampler.SAMPLING_LIMIT_RATE) == expectedRateLimit
+ span.getMetrics().get(RateByServiceSampler.SAMPLING_AGENT_RATE) == expectedAgentRate
+ span.getSamplingPriority() == expectedPriority
+
+ where:
+ serviceRules | operationRules | defaultRate | rateLimit | expectedRuleRate | expectedRateLimit | expectedAgentRate | expectedPriority
+ // Matching neither passes through to rate based sampler
+ "xx:1" | null | null | "50" | null | null | 1.0 | SAMPLER_KEEP
+ null | "xx:1" | null | "50" | null | null | 1.0 | SAMPLER_KEEP
+
+ // Matching neither with default rate
+ null | null | "1" | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+ null | null | "0" | "50" | 0 | null | null | SAMPLER_DROP
+ "xx:1" | null | "1" | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+ null | "xx:1" | "1" | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+ "xx:1" | null | "0" | "50" | 0 | null | null | SAMPLER_DROP
+ null | "xx:1" | "0" | "50" | 0 | null | null | SAMPLER_DROP
+
+ // Matching service: keep
+ "service:1" | null | null | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+ "s.*:1" | null | null | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+ ".*e:1" | null | null | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+ "[a-z]+:1" | null | null | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+
+ // Matching service: drop
+ "service:0" | null | null | "50" | 0 | null | null | SAMPLER_DROP
+ "s.*:0" | null | null | "50" | 0 | null | null | SAMPLER_DROP
+ ".*e:0" | null | null | "50" | 0 | null | null | SAMPLER_DROP
+ "[a-z]+:0" | null | null | "50" | 0 | null | null | SAMPLER_DROP
+
+ // Matching service overrides default rate
+ "service:1" | null | "0" | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+ "service:0" | null | "1" | "50" | 0 | null | null | SAMPLER_DROP
+
+ // multiple services
+ "xxx:0,service:1" | null | null | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+ "xxx:1,service:0" | null | null | "50" | 0 | null | null | SAMPLER_DROP
+
+ // Matching operation : keep
+ null | "operation:1" | null | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+ null | "o.*:1" | null | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+ null | ".*n:1" | null | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+ null | "[a-z]+:1" | null | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+
+ // Matching operation: drop
+ null | "operation:0" | null | "50" | 0 | null | null | SAMPLER_DROP
+ null | "o.*:0" | null | "50" | 0 | null | null | SAMPLER_DROP
+ null | ".*n:0" | null | "50" | 0 | null | null | SAMPLER_DROP
+ null | "[a-z]+:0" | null | "50" | 0 | null | null | SAMPLER_DROP
+
+ // Matching operation overrides default rate
+ null | "operation:1" | "0" | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+ null | "operation:0" | "1" | "50" | 0 | null | null | SAMPLER_DROP
+
+ // multiple operation combinations
+ null | "xxx:0,operation:1" | null | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+ null | "xxx:1,operation:0" | null | "50" | 0 | null | null | SAMPLER_DROP
+
+ // Service and operation name combinations
+ "service:1" | "operation:0" | null | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+ "service:1" | "xxx:0" | null | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+ "service:0" | "operation:1" | null | "50" | 0 | null | null | SAMPLER_DROP
+ "service:0" | "xxx:1" | null | "50" | 0 | null | null | SAMPLER_DROP
+ "xxx:0" | "operation:1" | null | "50" | 1.0 | 50 | null | SAMPLER_KEEP
+ "xxx:1" | "operation:0" | null | "50" | 0 | null | null | SAMPLER_DROP
+
+ // There are no tests for ordering within service or operation rules because the rule order in that case is unspecified
+ }
+
+ def "Rate limit is set for rate limited spans"() {
+ when:
+ Properties properties = new Properties()
+ properties.setProperty(TRACE_SAMPLING_SERVICE_RULES, "service:1")
+ properties.setProperty(TRACE_SAMPLING_RATE_LIMIT, "1")
+ Sampler sampler = Sampler.Builder.forConfig(properties)
+
+ DDSpan span1 = SpanFactory.newSpanOf("service", "bar")
+ DDSpan span2 = SpanFactory.newSpanOf("service", "bar")
+
+ ((PrioritySampler) sampler).setSamplingPriority(span1)
+ // Span 2 should be rate limited if there isn't a >1 sec delay between these 2 lines
+ ((PrioritySampler) sampler).setSamplingPriority(span2)
+
+ then:
+ span1.getMetrics().get(RuleBasedSampler.SAMPLING_RULE_RATE) == 1.0
+ span1.getMetrics().get(RuleBasedSampler.SAMPLING_LIMIT_RATE) == 1.0
+ span1.getMetrics().get(RateByServiceSampler.SAMPLING_AGENT_RATE) == null
+ span1.getSamplingPriority() == SAMPLER_KEEP
+
+ span2.getMetrics().get(RuleBasedSampler.SAMPLING_RULE_RATE) == 1.0
+ span2.getMetrics().get(RuleBasedSampler.SAMPLING_LIMIT_RATE) == 1.0
+ span2.getMetrics().get(RateByServiceSampler.SAMPLING_AGENT_RATE) == null
+ span2.getSamplingPriority() == SAMPLER_DROP
+ }
+
+ def "Rate limit is set for rate limited spans (matched on different rules)"() {
+ when:
+ Properties properties = new Properties()
+ properties.setProperty(TRACE_SAMPLING_SERVICE_RULES, "service:1,foo:1")
+ properties.setProperty(TRACE_SAMPLING_RATE_LIMIT, "1")
+ Sampler sampler = Sampler.Builder.forConfig(properties)
+
+ DDSpan span1 = SpanFactory.newSpanOf("service", "bar")
+ DDSpan span2 = SpanFactory.newSpanOf("foo", "bar")
+
+ ((PrioritySampler) sampler).setSamplingPriority(span1)
+ // Span 2 should be rate limited if there isn't a >1 sec delay between these 2 lines
+ ((PrioritySampler) sampler).setSamplingPriority(span2)
+
+ then:
+ span1.getMetrics().get(RuleBasedSampler.SAMPLING_RULE_RATE) == 1.0
+ span1.getMetrics().get(RuleBasedSampler.SAMPLING_LIMIT_RATE) == 1.0
+ span1.getMetrics().get(RateByServiceSampler.SAMPLING_AGENT_RATE) == null
+ span1.getSamplingPriority() == SAMPLER_KEEP
+
+ span2.getMetrics().get(RuleBasedSampler.SAMPLING_RULE_RATE) == 1.0
+ span2.getMetrics().get(RuleBasedSampler.SAMPLING_LIMIT_RATE) == 1.0
+ span2.getMetrics().get(RateByServiceSampler.SAMPLING_AGENT_RATE) == null
+ span2.getSamplingPriority() == SAMPLER_DROP
+ }
+}

Add tests for rules