-
Notifications
You must be signed in to change notification settings - Fork 344
Support DD_APM_TRACING_ENABLED=false for AI Guard traces #11885
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -6,6 +6,7 @@ | |||
| import datadog.trace.api.sampling.PrioritySampling; | ||||
| import datadog.trace.api.time.TimeSource; | ||||
| import datadog.trace.bootstrap.instrumentation.api.AgentTraceCollector; | ||||
| import datadog.trace.bootstrap.instrumentation.api.Tags; | ||||
| import datadog.trace.common.sampling.PrioritySampler; | ||||
| import java.util.concurrent.atomic.AtomicLongFieldUpdater; | ||||
| import javax.annotation.Nonnull; | ||||
|
|
@@ -65,11 +66,13 @@ public void setSamplingPriorityIfNecessary() { | |||
| DDSpan rootSpan = getRootSpan(); | ||||
| if (traceConfig.sampler instanceof PrioritySampler && rootSpan != null) { | ||||
| // Ignore the force-keep priority in the absence of propagated _dd.p.ts span tag marked for | ||||
| // ASM. | ||||
| // ASM. AI Guard traces (ai_guard.event=true) preserve the USER_KEEP priority set by | ||||
| // ai_guard.keep, bypassing the sampler override. | ||||
| if ((!Config.get().isApmTracingEnabled() | ||||
| && !ProductTraceSource.isProductMarked( | ||||
| rootSpan.spanContext().getPropagationTags().getTraceSource(), | ||||
| ProductTraceSource.ASM)) | ||||
| ProductTraceSource.ASM) | ||||
| && !Boolean.TRUE.equals(rootSpan.getTag(Tags.AI_GUARD_EVENT))) | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should add further product-specific tags to this code. Have you considered using dd-trace-java/dd-java-agent/appsec/src/main/java/com/datadog/appsec/ddwaf/WAFModule.java Line 443 in b622864
You'd just need to add your product to For example it could then become:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have considered this but I don't think ProductTraceSource is used in other tracers for AI Guard so I opted for consistency. @smola what do you think? |
||||
| || rootSpan.spanContext().getSamplingPriority() == PrioritySampling.UNSET) { | ||||
| ((PrioritySampler) traceConfig.sampler).setSamplingPriority(rootSpan); | ||||
| } | ||||
|
|
||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| package datadog.trace.common.sampling; | ||
|
|
||
| import static datadog.trace.api.config.AppSecConfig.APPSEC_ENABLED; | ||
| import static datadog.trace.api.config.GeneralConfig.APM_TRACING_ENABLED; | ||
| import static datadog.trace.api.sampling.PrioritySampling.SAMPLER_DROP; | ||
| import static datadog.trace.api.sampling.PrioritySampling.USER_KEEP; | ||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
|
||
| import datadog.trace.bootstrap.instrumentation.api.Tags; | ||
| import datadog.trace.common.writer.ListWriter; | ||
| import datadog.trace.core.CoreTracer; | ||
| import datadog.trace.core.DDCoreJavaSpecification; | ||
| import datadog.trace.core.DDSpan; | ||
| import datadog.trace.junit.utils.config.WithConfig; | ||
| import java.util.Map; | ||
| import org.junit.jupiter.api.BeforeEach; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| /** Verifies that AI Guard traces are kept regardless of APM/ASM configuration. */ | ||
| public class AIGuardSamplingTest extends DDCoreJavaSpecification { | ||
|
|
||
| private ListWriter writer; | ||
| private CoreTracer tracer; | ||
|
|
||
| @BeforeEach | ||
| void setUp() { | ||
| writer = new ListWriter(); | ||
| tracer = tracerBuilder().writer(writer).build(); | ||
| } | ||
|
|
||
| @Test | ||
| void aiGuardTraceIsKeptWhenApmEnabled() throws Exception { | ||
| DDSpan span = (DDSpan) tracer.buildSpan("datadog", "operation").start(); | ||
| span.setTag(Tags.AI_GUARD_KEEP, true); | ||
| span.setTag(Tags.AI_GUARD_EVENT, true); | ||
| span.finish(); | ||
| writer.waitForTraces(1); | ||
| assertEquals(USER_KEEP, (int) span.getSamplingPriority()); | ||
| assertDecisionMakerIsAiGuard(span); | ||
| } | ||
|
|
||
| @Test | ||
| @WithConfig(key = APM_TRACING_ENABLED, value = "false") | ||
| void aiGuardTraceIsKeptWhenApmAndAsmDisabled() throws Exception { | ||
| DDSpan span = (DDSpan) tracer.buildSpan("datadog", "operation").start(); | ||
| span.setTag(Tags.AI_GUARD_KEEP, true); | ||
| span.setTag(Tags.AI_GUARD_EVENT, true); | ||
| span.finish(); | ||
| writer.waitForTraces(1); | ||
| assertEquals(USER_KEEP, (int) span.getSamplingPriority()); | ||
| assertDecisionMakerIsAiGuard(span); | ||
| } | ||
|
|
||
| @Test | ||
| @WithConfig(key = APM_TRACING_ENABLED, value = "false") | ||
| @WithConfig(key = APPSEC_ENABLED, value = "true") | ||
| void aiGuardTraceIsKeptInAsmStandaloneMode() throws Exception { | ||
| DDSpan span = (DDSpan) tracer.buildSpan("datadog", "operation").start(); | ||
| span.setTag(Tags.AI_GUARD_KEEP, true); | ||
| span.setTag(Tags.AI_GUARD_EVENT, true); | ||
| span.finish(); | ||
| writer.waitForTraces(1); | ||
| assertEquals(USER_KEEP, (int) span.getSamplingPriority()); | ||
| assertDecisionMakerIsAiGuard(span); | ||
| } | ||
|
|
||
| /** ai_guard.event alone (without AI_GUARD_KEEP) must not bypass the sampler. */ | ||
| @Test | ||
| @WithConfig(key = APM_TRACING_ENABLED, value = "false") | ||
| @WithConfig(key = APPSEC_ENABLED, value = "true") | ||
| void aiGuardEventTagAloneDoesNotBypassSampler() throws Exception { | ||
| // consume the first allowed slot | ||
| DDSpan first = (DDSpan) tracer.buildSpan("datadog", "op").start(); | ||
| first.finish(); | ||
| writer.waitForTraces(1); | ||
|
|
||
| // second trace sets ai_guard.event but NOT AI_GUARD_KEEP — should still be dropped | ||
| DDSpan second = (DDSpan) tracer.buildSpan("datadog", "op").start(); | ||
| second.setTag(Tags.AI_GUARD_EVENT, true); | ||
| second.finish(); | ||
| writer.waitForTraces(2); | ||
|
|
||
| assertEquals(SAMPLER_DROP, (int) second.getSamplingPriority()); | ||
| } | ||
|
|
||
| /** | ||
| * AI Guard traces must be kept even when AsmStandaloneSampler has exhausted its rate-limit slot. | ||
| */ | ||
| @Test | ||
| @WithConfig(key = APM_TRACING_ENABLED, value = "false") | ||
| @WithConfig(key = APPSEC_ENABLED, value = "true") | ||
| void aiGuardTraceIsKeptAfterRateLimitSlotIsExhausted() throws Exception { | ||
| // consume the first allowed slot | ||
| DDSpan first = (DDSpan) tracer.buildSpan("datadog", "op").start(); | ||
| first.finish(); | ||
| writer.waitForTraces(1); | ||
|
|
||
| // AI Guard trace must still be force-kept even though the rate-limit slot is gone | ||
| DDSpan aiGuard = (DDSpan) tracer.buildSpan("datadog", "op").start(); | ||
| aiGuard.setTag(Tags.AI_GUARD_KEEP, true); | ||
| aiGuard.setTag(Tags.AI_GUARD_EVENT, true); | ||
| aiGuard.finish(); | ||
| writer.waitForTraces(2); | ||
|
|
||
| assertEquals(USER_KEEP, (int) aiGuard.getSamplingPriority()); | ||
| assertDecisionMakerIsAiGuard(aiGuard); | ||
| } | ||
|
|
||
| private static void assertDecisionMakerIsAiGuard(DDSpan span) { | ||
| Map<String, String> ptags = span.spanContext().getPropagationTags().createTagMap(); | ||
| assertEquals("-13", ptags.get("_dd.p.dm"), "_dd.p.dm must be -13 (AI Guard decision maker)"); | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.