diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/Reporter.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/Reporter.java index db6632b6d88..6dfb458b768 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/Reporter.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/Reporter.java @@ -8,6 +8,7 @@ import com.datadog.iast.model.VulnerabilityBatch; import com.datadog.iast.taint.TaintedObjects; import datadog.trace.api.Config; +import datadog.trace.api.ProductTraceSource; import datadog.trace.api.gateway.RequestContext; import datadog.trace.api.gateway.RequestContextSlot; import datadog.trace.api.internal.TraceSegment; @@ -125,7 +126,7 @@ private VulnerabilityBatch getOrCreateVulnerabilityBatch(final AgentSpan span) { // TODO: We need to check if we can have an API with more fine-grained semantics on why traces // are kept. segment.setTagTop(Tags.ASM_KEEP, true); - segment.setTagTop(Tags.PROPAGATED_APPSEC, true); + segment.setTagTop(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); return batch; } diff --git a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/ReporterTest.groovy b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/ReporterTest.groovy index fdba6f7f157..27ae2dfffdc 100644 --- a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/ReporterTest.groovy +++ b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/ReporterTest.groovy @@ -6,6 +6,7 @@ import com.datadog.iast.model.Vulnerability import com.datadog.iast.model.VulnerabilityBatch import com.datadog.iast.model.VulnerabilityType import datadog.trace.api.Config +import datadog.trace.api.ProductTraceSource import datadog.trace.api.gateway.RequestContext import datadog.trace.api.gateway.RequestContextSlot import datadog.trace.api.internal.TraceSegment @@ -85,7 +86,7 @@ class ReporterTest extends DDSpecification { ] }''', batch.toString(), true) 1 * traceSegment.setTagTop('asm.keep', true) - 1 * traceSegment.setTagTop('_dd.p.appsec', true) + 1 * traceSegment.setTagTop('_dd.p.ts', ProductTraceSource.ASM) 1 * reqCtx.getOrCreateMetaStructTop('_dd.stack', _) >> { stackTraceBatch } assertStackTrace(stackTraceBatch, v) 0 * _ @@ -135,7 +136,7 @@ class ReporterTest extends DDSpecification { ] }''', batch.toString(), true) 1 * traceSegment.setTagTop('asm.keep', true) - 1 * traceSegment.setTagTop('_dd.p.appsec', true) + 1 * traceSegment.setTagTop('_dd.p.ts', ProductTraceSource.ASM) 0 * _ } @@ -206,7 +207,7 @@ class ReporterTest extends DDSpecification { ] }''', batch.toString(), true) 1 * traceSegment.setTagTop('asm.keep', true) - 1 * traceSegment.setTagTop('_dd.p.appsec', true) + 1 * traceSegment.setTagTop('_dd.p.ts', ProductTraceSource.ASM) assertStackTrace(stackTraceBatch, [v1, v2] as Vulnerability[]) 0 * _ } @@ -331,7 +332,7 @@ class ReporterTest extends DDSpecification { 1 * traceSegment.getDataTop('iast') >> null 1 * traceSegment.setDataTop('iast', _ as VulnerabilityBatch) 1 * traceSegment.setTagTop('asm.keep', true) - 1 * traceSegment.setTagTop('_dd.p.appsec', true) + 1 * traceSegment.setTagTop('_dd.p.ts', ProductTraceSource.ASM) 1 * traceSegment.setTagTop('_dd.iast.enabled', 1) 1 * reqCtx.getOrCreateMetaStructTop('_dd.stack', _) >> new ConcurrentHashMap<>() 0 * _ diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java index 8e0ed020dba..a21bb0616c3 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java @@ -27,6 +27,7 @@ import com.datadog.appsec.report.AppSecEvent; import com.datadog.appsec.report.AppSecEventWrapper; import datadog.trace.api.Config; +import datadog.trace.api.ProductTraceSource; import datadog.trace.api.UserIdCollectionMode; import datadog.trace.api.gateway.Events; import datadog.trace.api.gateway.Flow; @@ -214,7 +215,7 @@ private Flow onUser( // span with ASM data segment.setTagTop(Tags.ASM_KEEP, true); - segment.setTagTop(Tags.PROPAGATED_APPSEC, true); + segment.setTagTop(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); // skip event if we have an SDK one if (mode != SDK) { @@ -275,7 +276,7 @@ private Flow onLoginEvent( // span with ASM data segment.setTagTop(Tags.ASM_KEEP, true); - segment.setTagTop(Tags.PROPAGATED_APPSEC, true); + segment.setTagTop(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); // update span tags segment.setTagTop("appsec.events." + eventName + ".track", true, true); @@ -789,7 +790,7 @@ private NoopFlow onRequestEnded(RequestContext ctx_, IGSpanInfo spanInfo) { if (!collectedEvents.isEmpty()) { // Set asm keep in case that root span was not available when events are detected traceSeg.setTagTop(Tags.ASM_KEEP, true); - traceSeg.setTagTop(Tags.PROPAGATED_APPSEC, true); + traceSeg.setTagTop(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); traceSeg.setTagTop("appsec.event", true); traceSeg.setTagTop("network.client.ip", ctx.getPeerAddress()); diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/powerwaf/PowerWAFModule.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/powerwaf/PowerWAFModule.java index 66ba35a9663..35562832c89 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/powerwaf/PowerWAFModule.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/powerwaf/PowerWAFModule.java @@ -26,6 +26,7 @@ import datadog.communication.monitor.Monitoring; import datadog.trace.api.Config; import datadog.trace.api.ProductActivation; +import datadog.trace.api.ProductTraceSource; import datadog.trace.api.gateway.Flow; import datadog.trace.api.telemetry.LogCollector; import datadog.trace.api.telemetry.WafMetricCollector; @@ -498,7 +499,9 @@ public void onDataAvailable( // If APM is disabled, inform downstream services that the current // distributed trace contains at least one ASM event and must inherit // the given force-keep priority - activeSpan.getLocalRootSpan().setTag(Tags.PROPAGATED_APPSEC, true); + activeSpan + .getLocalRootSpan() + .setTag(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM); } else { // If active span is not available the ASK_KEEP tag will be set in the GatewayBridge // when the request ends diff --git a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/gateway/GatewayBridgeSpecification.groovy b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/gateway/GatewayBridgeSpecification.groovy index 31e87449c92..e5285983003 100644 --- a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/gateway/GatewayBridgeSpecification.groovy +++ b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/gateway/GatewayBridgeSpecification.groovy @@ -8,6 +8,7 @@ import com.datadog.appsec.event.data.DataBundle import com.datadog.appsec.event.data.KnownAddresses import com.datadog.appsec.report.AppSecEvent import com.datadog.appsec.report.AppSecEventWrapper +import datadog.trace.api.ProductTraceSource import datadog.trace.api.UserIdCollectionMode import datadog.trace.api.appsec.LoginEventCallback import datadog.trace.api.function.TriConsumer @@ -1112,7 +1113,7 @@ class GatewayBridgeSpecification extends DDSpecification { 1 * traceSegment.setTagTop('appsec.events.users.signup.track', true, true) 1 * traceSegment.setTagTop('appsec.events.users.signup', ['key1': 'value1', 'key2': 'value2'], true) 1 * traceSegment.setTagTop('asm.keep', true) - 1 * traceSegment.setTagTop('_dd.p.appsec', true) + 1 * traceSegment.setTagTop('_dd.p.ts', ProductTraceSource.ASM) 1 * eventDispatcher.publishDataEvent(nonEmptyDsInfo, ctx.data, _ as DataBundle, _ as GatewayContext) >> { a, b, DataBundle db, GatewayContext gw -> if (mode == SDK) { assert db.get(KnownAddresses.USER_ID) == expectedUser @@ -1151,7 +1152,7 @@ class GatewayBridgeSpecification extends DDSpecification { 1 * traceSegment.setTagTop('appsec.events.users.login.success.track', true, true) 1 * traceSegment.setTagTop('appsec.events.users.login.success', ['key1': 'value1', 'key2': 'value2'], true) 1 * traceSegment.setTagTop('asm.keep', true) - 1 * traceSegment.setTagTop('_dd.p.appsec', true) + 1 * traceSegment.setTagTop('_dd.p.ts', ProductTraceSource.ASM) 1 * eventDispatcher.publishDataEvent(nonEmptyDsInfo, ctx.data, _ as DataBundle, _ as GatewayContext) >> { a, b, DataBundle db, GatewayContext gw -> if (mode == SDK) { assert db.get(KnownAddresses.USER_ID) == expectedUser @@ -1192,7 +1193,7 @@ class GatewayBridgeSpecification extends DDSpecification { 1 * traceSegment.setTagTop('appsec.events.users.login.failure.usr.exists', false, true) 1 * traceSegment.setTagTop('appsec.events.users.login.failure', ['key1': 'value1', 'key2': 'value2'], true) 1 * traceSegment.setTagTop('asm.keep', true) - 1 * traceSegment.setTagTop('_dd.p.appsec', true) + 1 * traceSegment.setTagTop('_dd.p.ts', ProductTraceSource.ASM) 1 * eventDispatcher.publishDataEvent(nonEmptyDsInfo, ctx.data, _ as DataBundle, _ as GatewayContext) >> { a, b, DataBundle db, GatewayContext gw -> if (mode == SDK) { assert db.get(KnownAddresses.USER_ID) == expectedUser @@ -1221,7 +1222,7 @@ class GatewayBridgeSpecification extends DDSpecification { 1 * traceSegment.setTagTop('appsec.events.my.event.track', true, true) 1 * traceSegment.setTagTop('appsec.events.my.event', ['key1': 'value1', 'key2': 'value2'], true) 1 * traceSegment.setTagTop('asm.keep', true) - 1 * traceSegment.setTagTop('_dd.p.appsec', true) + 1 * traceSegment.setTagTop('_dd.p.ts', ProductTraceSource.ASM) 0 * eventDispatcher.publishDataEvent } diff --git a/dd-smoke-tests/asm-standalone-billing/build.gradle b/dd-smoke-tests/apm-tracing-disabled/build.gradle similarity index 100% rename from dd-smoke-tests/asm-standalone-billing/build.gradle rename to dd-smoke-tests/apm-tracing-disabled/build.gradle diff --git a/dd-smoke-tests/asm-standalone-billing/gradle.lockfile b/dd-smoke-tests/apm-tracing-disabled/gradle.lockfile similarity index 100% rename from dd-smoke-tests/asm-standalone-billing/gradle.lockfile rename to dd-smoke-tests/apm-tracing-disabled/gradle.lockfile diff --git a/dd-smoke-tests/asm-standalone-billing/src/main/java/datadog/smoketest/asmstandalonebilling/AppConfig.java b/dd-smoke-tests/apm-tracing-disabled/src/main/java/datadog/smoketest/apmtracingdisabled/AppConfig.java similarity index 94% rename from dd-smoke-tests/asm-standalone-billing/src/main/java/datadog/smoketest/asmstandalonebilling/AppConfig.java rename to dd-smoke-tests/apm-tracing-disabled/src/main/java/datadog/smoketest/apmtracingdisabled/AppConfig.java index 3db04b37581..ec5c9e386fa 100644 --- a/dd-smoke-tests/asm-standalone-billing/src/main/java/datadog/smoketest/asmstandalonebilling/AppConfig.java +++ b/dd-smoke-tests/apm-tracing-disabled/src/main/java/datadog/smoketest/apmtracingdisabled/AppConfig.java @@ -1,4 +1,4 @@ -package datadog.smoketest.asmstandalonebilling; +package datadog.smoketest.apmtracingdisabled; import java.util.EnumSet; import javax.servlet.ServletContext; diff --git a/dd-smoke-tests/asm-standalone-billing/src/main/java/datadog/smoketest/asmstandalonebilling/Controller.java b/dd-smoke-tests/apm-tracing-disabled/src/main/java/datadog/smoketest/apmtracingdisabled/Controller.java similarity index 98% rename from dd-smoke-tests/asm-standalone-billing/src/main/java/datadog/smoketest/asmstandalonebilling/Controller.java rename to dd-smoke-tests/apm-tracing-disabled/src/main/java/datadog/smoketest/apmtracingdisabled/Controller.java index ebeecb88642..3bb55197614 100644 --- a/dd-smoke-tests/asm-standalone-billing/src/main/java/datadog/smoketest/asmstandalonebilling/Controller.java +++ b/dd-smoke-tests/apm-tracing-disabled/src/main/java/datadog/smoketest/apmtracingdisabled/Controller.java @@ -1,4 +1,4 @@ -package datadog.smoketest.asmstandalonebilling; +package datadog.smoketest.apmtracingdisabled; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.opentracing.Span; diff --git a/dd-smoke-tests/asm-standalone-billing/src/main/java/datadog/smoketest/asmstandalonebilling/SpringbootApplication.java b/dd-smoke-tests/apm-tracing-disabled/src/main/java/datadog/smoketest/apmtracingdisabled/SpringbootApplication.java similarity index 85% rename from dd-smoke-tests/asm-standalone-billing/src/main/java/datadog/smoketest/asmstandalonebilling/SpringbootApplication.java rename to dd-smoke-tests/apm-tracing-disabled/src/main/java/datadog/smoketest/apmtracingdisabled/SpringbootApplication.java index 0ac36d7d2f7..9d1916cd37b 100644 --- a/dd-smoke-tests/asm-standalone-billing/src/main/java/datadog/smoketest/asmstandalonebilling/SpringbootApplication.java +++ b/dd-smoke-tests/apm-tracing-disabled/src/main/java/datadog/smoketest/apmtracingdisabled/SpringbootApplication.java @@ -1,4 +1,4 @@ -package datadog.smoketest.asmstandalonebilling; +package datadog.smoketest.apmtracingdisabled; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/dd-smoke-tests/asm-standalone-billing/src/test/groovy/datadog/smoketest/asmstandalonebilling/AbstractAsmStandaloneBillingSmokeTest.groovy b/dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/AbstractApmTracingDisabledSmokeTest.groovy similarity index 92% rename from dd-smoke-tests/asm-standalone-billing/src/test/groovy/datadog/smoketest/asmstandalonebilling/AbstractAsmStandaloneBillingSmokeTest.groovy rename to dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/AbstractApmTracingDisabledSmokeTest.groovy index 8c8663fa946..bf7d1db9cee 100644 --- a/dd-smoke-tests/asm-standalone-billing/src/test/groovy/datadog/smoketest/asmstandalonebilling/AbstractAsmStandaloneBillingSmokeTest.groovy +++ b/dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/AbstractApmTracingDisabledSmokeTest.groovy @@ -1,10 +1,10 @@ -package datadog.smoketest.asmstandalonebilling +package datadog.smoketest.apmtracingdisabled import datadog.smoketest.AbstractServerSmokeTest import datadog.trace.api.sampling.PrioritySampling import datadog.trace.test.agent.decoder.DecodedTrace -abstract class AbstractAsmStandaloneBillingSmokeTest extends AbstractServerSmokeTest { +abstract class AbstractApmTracingDisabledSmokeTest extends AbstractServerSmokeTest { @Override File createTemporaryFile(int processIndex) { @@ -67,7 +67,7 @@ abstract class AbstractAsmStandaloneBillingSmokeTest extends AbstractServerSmoke } protected hasAppsecPropagationTag(DecodedTrace trace) { - return trace.spans[0].meta['_dd.p.appsec'] == "1" + return trace.spans[0].meta['_dd.p.ts'] == "02" } protected hasApmDisabledTag(DecodedTrace trace) { diff --git a/dd-smoke-tests/asm-standalone-billing/src/test/groovy/datadog/smoketest/asmstandalonebilling/AsmStandaloneBillingMatrixSmokeTest.groovy b/dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledMatrixSmokeTest.groovy similarity index 86% rename from dd-smoke-tests/asm-standalone-billing/src/test/groovy/datadog/smoketest/asmstandalonebilling/AsmStandaloneBillingMatrixSmokeTest.groovy rename to dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledMatrixSmokeTest.groovy index 4cd1731206d..2e9016ab218 100644 --- a/dd-smoke-tests/asm-standalone-billing/src/test/groovy/datadog/smoketest/asmstandalonebilling/AsmStandaloneBillingMatrixSmokeTest.groovy +++ b/dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledMatrixSmokeTest.groovy @@ -1,31 +1,31 @@ -package datadog.smoketest.asmstandalonebilling +package datadog.smoketest.apmtracingdisabled import datadog.trace.api.sampling.PrioritySampling import okhttp3.Request -class AsmStandaloneBillingMatrixSmokeTest extends AbstractAsmStandaloneBillingSmokeTest { +class ApmTracingDisabledMatrixSmokeTest extends AbstractApmTracingDisabledSmokeTest { - static final String STANDALONE_BILLING_SERVICE_NAME = "asm-standalone-billing-matrix-smoketest-app" - static final String STANDALONE_BILLING_SERVICE_NAME_2 = "asm-standalone-billing-matrix-smoketest-app2" + static final String APM_TRACING_DISABLED_SERVICE_NAME = "apm-tracing-disabled-matrix-smoketest-app" + static final String APM_TRACING_DISABLED_SERVICE_NAME_2 = "apm-tracing-disabled-matrix-smoketest-app2" static final String APM_ENABLED_SERVICE_NAME = "apm-enabled-matrix-smoketest-app" static final String ASM_ENABLED_SERVICE_NAME = "asm-enabled-matrix-smoketest-app" - static final String[] STANDALONE_BILLING_PROPERTIES = [ - "-Ddd.experimental.appsec.standalone.enabled=true", + static final String[] APM_TRACING_DISABLED_PROPERTIES = [ + "-Ddd.apm.tracing.enabled=false", "-Ddd.iast.enabled=true", "-Ddd.iast.detection.mode=FULL", "-Ddd.iast.debug.enabled=true", "-Ddd.trace.tracer.metrics.enabled=true", - "-Ddd.service.name=${STANDALONE_BILLING_SERVICE_NAME}", + "-Ddd.service.name=${APM_TRACING_DISABLED_SERVICE_NAME}", ] - static final String[] STANDALONE_BILLING_PROPERTIES_2 = [ - "-Ddd.experimental.appsec.standalone.enabled=true", + static final String[] APM_TRACING_DISABLED_PROPERTIES_2 = [ + "-Ddd.apm.tracing.enabled=false", "-Ddd.iast.enabled=true", "-Ddd.iast.detection.mode=FULL", "-Ddd.iast.debug.enabled=true", "-Ddd.trace.tracer.metrics.enabled=true", - "-Ddd.service.name=${STANDALONE_BILLING_SERVICE_NAME_2}", + "-Ddd.service.name=${APM_TRACING_DISABLED_SERVICE_NAME_2}", ] static final String[] APM_ENABLED_PROPERTIES = ["-Ddd.service.name=${APM_ENABLED_SERVICE_NAME}", "-Ddd.trace.tracer.metrics.enabled=true",] @@ -46,13 +46,13 @@ class AsmStandaloneBillingMatrixSmokeTest extends AbstractAsmStandaloneBillingSm ProcessBuilder createProcessBuilder(int processIndex) { switch (processIndex) { case 0: - return createProcess(processIndex, STANDALONE_BILLING_PROPERTIES) + return createProcess(processIndex, APM_TRACING_DISABLED_PROPERTIES) case 1: return createProcess(processIndex, APM_ENABLED_PROPERTIES) case 2: return createProcess(processIndex, ASM_ENABLED_PROPERTIES) case 3: - return createProcess(processIndex, STANDALONE_BILLING_PROPERTIES_2) + return createProcess(processIndex, APM_TRACING_DISABLED_PROPERTIES_2) default: throw new IllegalArgumentException("Invalid process index: ${processIndex}") } @@ -82,7 +82,7 @@ class AsmStandaloneBillingMatrixSmokeTest extends AbstractAsmStandaloneBillingSm !hasApmDisabledTag (upstreamTrace) and:"No ASM events, resulting in the local sampling decision" - def standAloneBillingTrace = getServiceTrace(STANDALONE_BILLING_SERVICE_NAME) + def standAloneBillingTrace = getServiceTrace(APM_TRACING_DISABLED_SERVICE_NAME) isSampledBySampler(standAloneBillingTrace) !hasAppsecPropagationTag (standAloneBillingTrace) hasApmDisabledTag (standAloneBillingTrace) @@ -118,7 +118,7 @@ class AsmStandaloneBillingMatrixSmokeTest extends AbstractAsmStandaloneBillingSm !hasApmDisabledTag (upstreamTrace) and:"ASM events" - def standAloneBillingTrace = getServiceTrace(STANDALONE_BILLING_SERVICE_NAME) + def standAloneBillingTrace = getServiceTrace(APM_TRACING_DISABLED_SERVICE_NAME) checkRootSpanPrioritySampling(standAloneBillingTrace, PrioritySampling.USER_KEEP) hasAppsecPropagationTag (standAloneBillingTrace) hasApmDisabledTag (standAloneBillingTrace) @@ -154,7 +154,7 @@ class AsmStandaloneBillingMatrixSmokeTest extends AbstractAsmStandaloneBillingSm !hasApmDisabledTag (upstreamTrace) and:"No ASM events, resulting in the local sampling decision" - def standAloneBillingTrace = getServiceTrace(STANDALONE_BILLING_SERVICE_NAME) + def standAloneBillingTrace = getServiceTrace(APM_TRACING_DISABLED_SERVICE_NAME) isSampledBySampler(standAloneBillingTrace) !hasAppsecPropagationTag (standAloneBillingTrace) hasApmDisabledTag (standAloneBillingTrace) @@ -184,13 +184,13 @@ class AsmStandaloneBillingMatrixSmokeTest extends AbstractAsmStandaloneBillingSm waitForTraceCount(3) and: "Upstream standalone ASM service having ASM events result in force keep and propagation of the tag" - def upstreamTrace = getServiceTrace(STANDALONE_BILLING_SERVICE_NAME_2) + def upstreamTrace = getServiceTrace(APM_TRACING_DISABLED_SERVICE_NAME_2) checkRootSpanPrioritySampling(upstreamTrace, PrioritySampling.USER_KEEP) hasAppsecPropagationTag (upstreamTrace) hasApmDisabledTag (upstreamTrace) and:"standalone service must keep the local trace with the local sampling priority" - def standAloneBillingTrace = getServiceTrace(STANDALONE_BILLING_SERVICE_NAME) + def standAloneBillingTrace = getServiceTrace(APM_TRACING_DISABLED_SERVICE_NAME) checkRootSpanPrioritySampling(standAloneBillingTrace, PrioritySampling.USER_KEEP) hasAppsecPropagationTag (standAloneBillingTrace) hasApmDisabledTag (standAloneBillingTrace) @@ -224,11 +224,11 @@ class AsmStandaloneBillingMatrixSmokeTest extends AbstractAsmStandaloneBillingSm def upstreamTraceId = getServiceTrace(APM_ENABLED_SERVICE_NAME).spans[0].traceId and: 'No ASM events, resulting in the local sampling decision' - def standAloneBillingTrace = getServiceTrace(STANDALONE_BILLING_SERVICE_NAME) + def standAloneBillingTrace = getServiceTrace(APM_TRACING_DISABLED_SERVICE_NAME) isSampledBySampler(standAloneBillingTrace) !hasAppsecPropagationTag (standAloneBillingTrace) hasApmDisabledTag (standAloneBillingTrace) - def standAloneBillingTraceId = getServiceTrace(STANDALONE_BILLING_SERVICE_NAME).spans[0].traceId + def standAloneBillingTraceId = getServiceTrace(APM_TRACING_DISABLED_SERVICE_NAME).spans[0].traceId upstreamTraceId == standAloneBillingTraceId //There is propagation and: 'Propagation is stopped' @@ -255,18 +255,18 @@ class AsmStandaloneBillingMatrixSmokeTest extends AbstractAsmStandaloneBillingSm waitForTraceCount(3) and: 'Upstream ASM events' - def upstreamTrace = getServiceTrace(STANDALONE_BILLING_SERVICE_NAME_2) + def upstreamTrace = getServiceTrace(APM_TRACING_DISABLED_SERVICE_NAME_2) checkRootSpanPrioritySampling(upstreamTrace, PrioritySampling.USER_KEEP) hasAppsecPropagationTag (upstreamTrace) hasApmDisabledTag (upstreamTrace) - def upstreamTraceId = getServiceTrace(STANDALONE_BILLING_SERVICE_NAME_2).spans[0].traceId + def upstreamTraceId = getServiceTrace(APM_TRACING_DISABLED_SERVICE_NAME_2).spans[0].traceId and: 'No ASM events, resulting in the local sampling decision' - def standAloneBillingTrace = getServiceTrace(STANDALONE_BILLING_SERVICE_NAME) + def standAloneBillingTrace = getServiceTrace(APM_TRACING_DISABLED_SERVICE_NAME) checkRootSpanPrioritySampling(standAloneBillingTrace, PrioritySampling.USER_KEEP) hasAppsecPropagationTag (standAloneBillingTrace) hasApmDisabledTag (standAloneBillingTrace) - def standAloneBillingTraceId = getServiceTrace(STANDALONE_BILLING_SERVICE_NAME).spans[0].traceId + def standAloneBillingTraceId = getServiceTrace(APM_TRACING_DISABLED_SERVICE_NAME).spans[0].traceId upstreamTraceId == standAloneBillingTraceId //There is propagation and: 'Default APM distributed tracing behavior with' @@ -300,11 +300,11 @@ class AsmStandaloneBillingMatrixSmokeTest extends AbstractAsmStandaloneBillingSm def upstreamTraceId = getServiceTrace(APM_ENABLED_SERVICE_NAME).spans[0].traceId and: 'ASM events, resulting in force keep and appsec propagation' - def standAloneBillingTrace = getServiceTrace(STANDALONE_BILLING_SERVICE_NAME) + def standAloneBillingTrace = getServiceTrace(APM_TRACING_DISABLED_SERVICE_NAME) checkRootSpanPrioritySampling(standAloneBillingTrace, PrioritySampling.USER_KEEP) hasAppsecPropagationTag (standAloneBillingTrace) hasApmDisabledTag (standAloneBillingTrace) - def standAloneBillingTraceId = getServiceTrace(STANDALONE_BILLING_SERVICE_NAME).spans[0].traceId + def standAloneBillingTraceId = getServiceTrace(APM_TRACING_DISABLED_SERVICE_NAME).spans[0].traceId upstreamTraceId == standAloneBillingTraceId //There is propagation and: 'Default APM distributed tracing behavior with' diff --git a/dd-smoke-tests/asm-standalone-billing/src/test/groovy/datadog/smoketest/asmstandalonebilling/AsmStandaloneBillingSamplingSmokeTest.groovy b/dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledSamplingSmokeTest.groovy similarity index 95% rename from dd-smoke-tests/asm-standalone-billing/src/test/groovy/datadog/smoketest/asmstandalonebilling/AsmStandaloneBillingSamplingSmokeTest.groovy rename to dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledSamplingSmokeTest.groovy index 27f037d4db1..126e918344c 100644 --- a/dd-smoke-tests/asm-standalone-billing/src/test/groovy/datadog/smoketest/asmstandalonebilling/AsmStandaloneBillingSamplingSmokeTest.groovy +++ b/dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledSamplingSmokeTest.groovy @@ -1,4 +1,4 @@ -package datadog.smoketest.asmstandalonebilling +package datadog.smoketest.apmtracingdisabled import datadog.trace.api.sampling.PrioritySampling import datadog.trace.test.util.Flaky @@ -6,17 +6,17 @@ import groovy.json.JsonSlurper import okhttp3.Request @Flaky -class AsmStandaloneBillingSamplingSmokeTest extends AbstractAsmStandaloneBillingSmokeTest { +class ApmTracingDisabledSamplingSmokeTest extends AbstractApmTracingDisabledSmokeTest { @Override ProcessBuilder createProcessBuilder(){ final String[] processProperties = [ - "-Ddd.experimental.appsec.standalone.enabled=true", + "-Ddd.apm.tracing.enabled=false", "-Ddd.iast.enabled=true", "-Ddd.appsec.enabled=true", "-Ddd.iast.detection.mode=FULL", "-Ddd.iast.debug.enabled=true", - "-Ddd.service.name=asm-standalone-billing-sampling-spring-smoketest-app", + "-Ddd.service.name=apm-tracing-disabled-sampling-spring-smoketest-app", ] return createProcess(processProperties) } diff --git a/dd-smoke-tests/asm-standalone-billing/src/test/groovy/datadog/smoketest/asmstandalonebilling/AsmStandaloneBillingSmokeTest.groovy b/dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledSmokeTest.groovy similarity index 80% rename from dd-smoke-tests/asm-standalone-billing/src/test/groovy/datadog/smoketest/asmstandalonebilling/AsmStandaloneBillingSmokeTest.groovy rename to dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledSmokeTest.groovy index f5d7761b676..b84782da595 100644 --- a/dd-smoke-tests/asm-standalone-billing/src/test/groovy/datadog/smoketest/asmstandalonebilling/AsmStandaloneBillingSmokeTest.groovy +++ b/dd-smoke-tests/apm-tracing-disabled/src/test/groovy/datadog/smoketest/apmtracingdisabled/ApmTracingDisabledSmokeTest.groovy @@ -1,20 +1,20 @@ -package datadog.smoketest.asmstandalonebilling +package datadog.smoketest.apmtracingdisabled import okhttp3.Request -class AsmStandaloneBillingSmokeTest extends AbstractAsmStandaloneBillingSmokeTest { +class ApmTracingDisabledSmokeTest extends AbstractApmTracingDisabledSmokeTest { - private static final String STANDALONE_BILLING_SERVICE_NAME = "asm-standalone-billing-smoketest-app" + private static final String APM_TRACING_DISABLED_SERVICE_NAME = "asm-standalone-billing-smoketest-app" private static final String APM_ENABLED_SERVICE_NAME = "apm-enabled-smoketest-app" - static final String[] STANDALONE_BILLING_PROPERTIES = [ - "-Ddd.experimental.appsec.standalone.enabled=true", + static final String[] APM_TRACING_DISABLED_PROPERTIES = [ + "-Ddd.apm.tracing.enabled=false", "-Ddd.iast.enabled=true", "-Ddd.iast.detection.mode=FULL", "-Ddd.iast.debug.enabled=true", "-Ddd.appsec.enabled=true", "-Ddd.trace.tracer.metrics.enabled=true", - "-Ddd.service.name=${STANDALONE_BILLING_SERVICE_NAME}", + "-Ddd.service.name=${APM_TRACING_DISABLED_SERVICE_NAME}", ] static final String[] APM_ENABLED_PROPERTIES = ["-Ddd.service.name=${APM_ENABLED_SERVICE_NAME}", "-Ddd.trace.tracer.metrics.enabled=true",] @@ -26,7 +26,7 @@ class AsmStandaloneBillingSmokeTest extends AbstractAsmStandaloneBillingSmokeTes @Override ProcessBuilder createProcessBuilder(int processIndex) { if(processIndex == 0){ - return createProcess(processIndex, STANDALONE_BILLING_PROPERTIES) + return createProcess(processIndex, APM_TRACING_DISABLED_PROPERTIES) } return createProcess(processIndex, APM_ENABLED_PROPERTIES) } @@ -46,7 +46,7 @@ class AsmStandaloneBillingSmokeTest extends AbstractAsmStandaloneBillingSmokeTes response1.successful response2.successful waitForTraceCount(2) - hasApmDisabledTag(getServiceTrace(STANDALONE_BILLING_SERVICE_NAME)) + hasApmDisabledTag(getServiceTrace(APM_TRACING_DISABLED_SERVICE_NAME)) !hasApmDisabledTag(getServiceTrace(APM_ENABLED_SERVICE_NAME)) } @@ -68,7 +68,7 @@ class AsmStandaloneBillingSmokeTest extends AbstractAsmStandaloneBillingSmokeTes isLogPresent { it.contains('datadog.trace.agent.common.metrics.MetricsAggregatorFactory - tracer metrics disabled') } } - void 'test _dd.p.appsec propagation for appsec event'() { + void 'test _dd.p.ts propagation for appsec event'() { setup: final downstreamUrl = "http://localhost:${httpPorts[1]}/rest-api/greetings" final url = localUrl + "url=${downstreamUrl}" @@ -77,7 +77,7 @@ class AsmStandaloneBillingSmokeTest extends AbstractAsmStandaloneBillingSmokeTes when: "Request to an endpoint that triggers ASM events and then calls another endpoint" final response1 = client.newCall(request).execute() - then: "Both traces should have a root span with _dd.p.appsec=1 tag" + then: "Both traces should have a root span with _dd.p.ts=02 tag" response1.successful waitForTraceCount(2) assert traces.size() == 2 diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/AppSecConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/AppSecConfig.java index 1551a419cce..454ef0a5425 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/AppSecConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/AppSecConfig.java @@ -40,7 +40,5 @@ public final class AppSecConfig { public static final String APPSEC_MAX_STACKTRACE_DEPTH_DEPRECATED = "appsec.max.stacktrace.depth"; // old non-standard as a fallback alias - public static final String APPSEC_STANDALONE_ENABLED = "experimental.appsec.standalone.enabled"; - private AppSecConfig() {} } diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java index 524dde00dcb..9a5caf5c4a2 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/GeneralConfig.java @@ -93,6 +93,7 @@ public final class GeneralConfig { "telemetry.dependency.resolution.period.millis"; public static final String AGENTLESS_LOG_SUBMISSION_LEVEL = "agentless.log.submission.level"; public static final String AGENTLESS_LOG_SUBMISSION_URL = "agentless.log.submission.url"; + public static final String APM_TRACING_ENABLED = "apm.tracing.enabled"; private GeneralConfig() {} } diff --git a/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java b/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java index 8638d20205a..54a2d750700 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/sampling/AsmStandaloneSampler.java @@ -1,5 +1,8 @@ package datadog.trace.common.sampling; +import static datadog.trace.api.sampling.PrioritySampling.SAMPLER_DROP; +import static datadog.trace.api.sampling.PrioritySampling.SAMPLER_KEEP; + import datadog.trace.api.sampling.SamplingMechanism; import datadog.trace.core.CoreSpan; import java.time.Clock; @@ -39,10 +42,10 @@ public > void setSamplingPriority(final T span) { if (shouldSample()) { log.debug("Set SAMPLER_KEEP for span {}", span.getSpanId()); - span.setSamplingPriority(PrioritySampling.SAMPLER_KEEP, SamplingMechanism.APPSEC); + span.setSamplingPriority(SAMPLER_KEEP, SamplingMechanism.APPSEC); } else { log.debug("Set SAMPLER_DROP for span {}", span.getSpanId()); - span.setSamplingPriority(PrioritySampling.SAMPLER_DROP, SamplingMechanism.APPSEC); + span.setSamplingPriority(SAMPLER_DROP, SamplingMechanism.APPSEC); } } diff --git a/dd-trace-core/src/main/java/datadog/trace/common/sampling/Sampler.java b/dd-trace-core/src/main/java/datadog/trace/common/sampling/Sampler.java index 150b67e6b59..eb255b66328 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/sampling/Sampler.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/sampling/Sampler.java @@ -4,6 +4,7 @@ import static datadog.trace.bootstrap.instrumentation.api.SamplerConstants.KEEP; import datadog.trace.api.Config; +import datadog.trace.api.ProductActivation; import datadog.trace.api.TraceConfig; import datadog.trace.api.config.TracerConfig; import datadog.trace.api.sampling.PrioritySampling; @@ -35,7 +36,9 @@ final class Builder { public static Sampler forConfig(final Config config, final TraceConfig traceConfig) { Sampler sampler; if (config != null) { - if (config.isAppSecStandaloneEnabled()) { + if (!config.isApmTracingEnabled() + && (config.getAppSecActivation() == ProductActivation.FULLY_ENABLED + || config.getIastActivation() == ProductActivation.FULLY_ENABLED)) { log.debug("APM is disabled. Only 1 trace per minute will be sent."); return new AsmStandaloneSampler(Clock.systemUTC()); } diff --git a/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/DDAgentApi.java b/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/DDAgentApi.java index 92af3027b91..645bbc4b9e9 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/DDAgentApi.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/DDAgentApi.java @@ -112,7 +112,7 @@ public Response sendSerializedTraces(final Payload payload) { (metricsEnabled && featuresDiscovery.supportsMetrics()) // Disabling the computation agent-side of the APM trace metrics by // pretending it was already done by the library - || Config.get().isAppSecStandaloneEnabled() + || !Config.get().isApmTracingEnabled() ? "true" : "") .put(payload.toRequest()) diff --git a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java index 4b3d2e50b4a..668cff57a1f 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java @@ -86,11 +86,11 @@ import datadog.trace.core.monitor.HealthMetrics; import datadog.trace.core.monitor.MonitoringImpl; import datadog.trace.core.monitor.TracerHealthMetrics; +import datadog.trace.core.propagation.ApmTracingDisabledPropagator; import datadog.trace.core.propagation.CorePropagation; import datadog.trace.core.propagation.ExtractedContext; import datadog.trace.core.propagation.HttpCodec; import datadog.trace.core.propagation.PropagationTags; -import datadog.trace.core.propagation.StandaloneAsmPropagator; import datadog.trace.core.propagation.TracingPropagator; import datadog.trace.core.propagation.XRayPropagator; import datadog.trace.core.scopemanager.ContinuableScopeManager; @@ -721,14 +721,16 @@ private CoreTracer( HttpCodec.Extractor tracingExtractor = extractor == null ? HttpCodec.createExtractor(config, this::captureTraceConfig) : extractor; TracingPropagator tracingPropagator = new TracingPropagator(injector, tracingExtractor); - // Check if standalone AppSec is enabled: - // If enabled, use the standalone AppSec propagator by default that will limit tracing concern + // Check if apm tracing is disabled: + // If disabled, use the APM tracing disabled propagator by default that will limit tracing + // concern // injection and delegate to the tracing propagator if needed, // If disabled, the most common case, use the usual tracing propagator by default. - boolean standaloneAppSec = config.isAppSecStandaloneEnabled(); + boolean apmTracingDisabled = !config.isApmTracingEnabled(); boolean dsm = config.isDataStreamsEnabled(); - Propagators.register(STANDALONE_ASM_CONCERN, new StandaloneAsmPropagator(), standaloneAppSec); - Propagators.register(TRACING_CONCERN, tracingPropagator, !standaloneAppSec); + Propagators.register( + STANDALONE_ASM_CONCERN, new ApmTracingDisabledPropagator(), apmTracingDisabled); + Propagators.register(TRACING_CONCERN, tracingPropagator, !apmTracingDisabled); Propagators.register(XRAY_TRACING_CONCERN, new XRayPropagator(config), false); if (dsm) { Propagators.register(DSM_CONCERN, this.dataStreamsMonitoring.propagator()); diff --git a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java index fcbf046122a..bce7d8800f3 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java @@ -512,8 +512,8 @@ private void forceKeepThisSpan(byte samplingMechanism) { } } - public void updateAppsecPropagation(boolean value) { - propagationTags.updateAppsecPropagation(value); + public void addPropagatedTraceSource(final int value) { + propagationTags.addTraceSource(value); } public void updateDebugPropagation(String value) { diff --git a/dd-trace-core/src/main/java/datadog/trace/core/TraceCollector.java b/dd-trace-core/src/main/java/datadog/trace/core/TraceCollector.java index 260379ad4d3..777fc3889bf 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/TraceCollector.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/TraceCollector.java @@ -2,6 +2,7 @@ import datadog.trace.api.Config; import datadog.trace.api.DDTraceId; +import datadog.trace.api.ProductTraceSource; import datadog.trace.api.sampling.PrioritySampling; import datadog.trace.api.time.TimeSource; import datadog.trace.bootstrap.instrumentation.api.AgentTraceCollector; @@ -63,9 +64,11 @@ public void setSamplingPriorityIfNecessary() { // Locks inside DDSpanContext ensure the correct behavior in the race case DDSpan rootSpan = getRootSpan(); if (traceConfig.sampler instanceof PrioritySampler && rootSpan != null) { - // Ignore the force-keep priority in the absence of propagated _dd.p.appsec span tag. - if ((Config.get().isAppSecStandaloneEnabled() - && !rootSpan.context().getPropagationTags().isAppsecPropagationEnabled()) + // Ignore the force-keep priority in the absence of propagated _dd.p.ts span tag marked for + // ASM. + if ((!Config.get().isApmTracingEnabled() + && !ProductTraceSource.isProductMarked( + rootSpan.context().getPropagationTags().getTraceSource(), ProductTraceSource.ASM)) || rootSpan.context().getSamplingPriority() == PrioritySampling.UNSET) { ((PrioritySampler) traceConfig.sampler).setSamplingPriority(rootSpan); } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/propagation/StandaloneAsmPropagator.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ApmTracingDisabledPropagator.java similarity index 78% rename from dd-trace-core/src/main/java/datadog/trace/core/propagation/StandaloneAsmPropagator.java rename to dd-trace-core/src/main/java/datadog/trace/core/propagation/ApmTracingDisabledPropagator.java index fc208c5de80..8dfe988d6a6 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/propagation/StandaloneAsmPropagator.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ApmTracingDisabledPropagator.java @@ -8,33 +8,34 @@ import datadog.context.propagation.CarrierVisitor; import datadog.context.propagation.Propagator; import datadog.context.propagation.Propagators; +import datadog.trace.api.ProductTraceSource; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext; import datadog.trace.core.DDSpanContext; import javax.annotation.ParametersAreNonnullByDefault; @ParametersAreNonnullByDefault -public class StandaloneAsmPropagator implements Propagator { +public class ApmTracingDisabledPropagator implements Propagator { @Override public void inject(Context context, C carrier, CarrierSetter setter) { - // Stop propagation if appsec propagation is disabled (no ASM events), stop propagation + // Stop propagation if no product events, stop propagation AgentSpan span; if ((span = fromContext(context)) != null) { AgentSpanContext spanContext = span.context(); if (spanContext instanceof DDSpanContext) { DDSpanContext ddSpanContext = (DDSpanContext) spanContext; - if (!ddSpanContext.getPropagationTags().isAppsecPropagationEnabled()) { + if (ddSpanContext.getPropagationTags().getTraceSource() == ProductTraceSource.UNSET) { return; } } - // Only propagate tracing for appsec standalone product + // Only propagate tracing if trace source set Propagators.forConcern(TRACING_CONCERN).inject(span, carrier, setter); } } @Override public Context extract(Context context, C carrier, CarrierVisitor visitor) { - // Only propagate tracing for appsec standalone product + // Only propagate tracing if trace source set return Propagators.forConcern(TRACING_CONCERN).extract(context, carrier, visitor); } } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/propagation/PropagationTags.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/PropagationTags.java index b770ac703c7..7d8ad25a44d 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/propagation/PropagationTags.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/PropagationTags.java @@ -3,6 +3,7 @@ import static datadog.trace.api.ConfigDefaults.DEFAULT_TRACE_X_DATADOG_TAGS_MAX_LENGTH; import datadog.trace.api.Config; +import datadog.trace.api.ProductTraceSource; import datadog.trace.core.propagation.ptags.PTagsFactory; import java.util.HashMap; import java.util.Map; @@ -100,10 +101,28 @@ public interface Factory { */ public abstract void fillTagMap(Map tagMap); - /** Add the appsec propagation tag to the propagation tags. */ - public abstract void updateAppsecPropagation(boolean enabled); + /** + * Updates the trace source to include the specified product. + * + *

The product value is parsed and interpreted according to the logic in {@link + * ProductTraceSource}. This method ensures that the given product is marked as part of the trace + * source. + * + * @param product the product identifier to be added to the trace source. Refer to {@link + * ProductTraceSource} for details on how the value is interpreted. + */ + public abstract void addTraceSource(int product); - public abstract boolean isAppsecPropagationEnabled(); + /** + * Retrieves the current trace source. + * + *

The returned value is an encoded bitfield that represents the included products. To + * understand how this value is parsed and interpreted, refer to {@link ProductTraceSource}. + * + * @return the trace source as an integer bitfield. See {@link ProductTraceSource} for details on + * its structure and usage. + */ + public abstract int getTraceSource(); public abstract void updateDebugPropagation(String value); diff --git a/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/DatadogPTagsCodec.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/DatadogPTagsCodec.java index e5731e44a89..f01b3f40005 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/DatadogPTagsCodec.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/DatadogPTagsCodec.java @@ -1,5 +1,6 @@ package datadog.trace.core.propagation.ptags; +import datadog.trace.api.ProductTraceSource; import datadog.trace.core.propagation.PropagationTags; import datadog.trace.core.propagation.ptags.PTagsFactory.PTags; import datadog.trace.core.propagation.ptags.TagElement.Encoding; @@ -61,7 +62,7 @@ PropagationTags fromHeaderValue(PTagsFactory tagsFactory, String value) { int tagPos = 0; TagValue decisionMakerTagValue = null; TagValue traceIdTagValue = null; - boolean appsecPropagationEnabled = false; + int traceSource = 0; while (tagPos < len) { int tagKeyEndsAt = validateCharsUntilSeparatorOrEnd( @@ -96,8 +97,8 @@ PropagationTags fromHeaderValue(PTagsFactory tagsFactory, String value) { decisionMakerTagValue = tagValue; } else if (tagKey.equals(TRACE_ID_TAG)) { traceIdTagValue = tagValue; - } else if (tagKey.equals(APPSEC_TAG)) { - appsecPropagationEnabled = tagValue.charAt(0) == '1'; + } else if (tagKey.equals(TRACE_SOURCE_TAG)) { + traceSource = ProductTraceSource.parseBitfieldHex(tagValue.toString()); } else { if (tagPairs == null) { // This is roughly the size of a two element linked list but can hold six @@ -110,8 +111,7 @@ PropagationTags fromHeaderValue(PTagsFactory tagsFactory, String value) { } tagPos = tagValueEndsAt + 1; } - return tagsFactory.createValid( - tagPairs, decisionMakerTagValue, traceIdTagValue, appsecPropagationEnabled); + return tagsFactory.createValid(tagPairs, decisionMakerTagValue, traceIdTagValue, traceSource); } @Override diff --git a/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/PTagsCodec.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/PTagsCodec.java index 31796025b91..2dde4f84a87 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/PTagsCodec.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/PTagsCodec.java @@ -2,6 +2,7 @@ import static datadog.trace.core.propagation.ptags.PTagsFactory.PROPAGATION_ERROR_TAG_KEY; +import datadog.trace.api.ProductTraceSource; import datadog.trace.core.propagation.PropagationTags; import datadog.trace.core.propagation.ptags.PTagsFactory.PTags; import datadog.trace.core.propagation.ptags.TagElement.Encoding; @@ -15,12 +16,11 @@ abstract class PTagsCodec { protected static final TagKey DECISION_MAKER_TAG = TagKey.from("dm"); protected static final TagKey TRACE_ID_TAG = TagKey.from("tid"); - protected static final TagKey APPSEC_TAG = TagKey.from("appsec"); + protected static final TagKey TRACE_SOURCE_TAG = TagKey.from("ts"); protected static final TagKey DEBUG_TAG = TagKey.from("debug"); protected static final String PROPAGATION_ERROR_MALFORMED_TID = "malformed_tid "; protected static final String PROPAGATION_ERROR_INCONSISTENT_TID = "inconsistent_tid "; protected static final TagKey UPSTREAM_SERVICES_DEPRECATED_TAG = TagKey.from("upstream_services"); - protected static final TagValue APPSEC_ENABLED_TAG_VALUE = TagValue.from("1"); static String headerValue(PTagsCodec codec, PTags ptags) { int estimate = codec.estimateHeaderSize(ptags); @@ -38,8 +38,13 @@ static String headerValue(PTagsCodec codec, PTags ptags) { if (ptags.getTraceIdHighOrderBitsHexTagValue() != null) { size = codec.appendTag(sb, TRACE_ID_TAG, ptags.getTraceIdHighOrderBitsHexTagValue(), size); } - if (ptags.isAppsecPropagationEnabled()) { - size = codec.appendTag(sb, APPSEC_TAG, APPSEC_ENABLED_TAG_VALUE, size); + if (ptags.getTraceSource() != ProductTraceSource.UNSET) { + size = + codec.appendTag( + sb, + TRACE_SOURCE_TAG, + TagValue.from(ProductTraceSource.getBitfieldHex(ptags.getTraceSource())), + size); } if (ptags.getDebugPropagation() != null) { size = codec.appendTag(sb, DEBUG_TAG, TagValue.from(ptags.getDebugPropagation()), size); @@ -87,10 +92,12 @@ static void fillTagMap(PTags propagationTags, Map tagMap) { DECISION_MAKER_TAG.forType(Encoding.DATADOG).toString(), propagationTags.getDecisionMakerTagValue().forType(Encoding.DATADOG).toString()); } - if (propagationTags.isAppsecPropagationEnabled()) { + if (propagationTags.getTraceSource() != ProductTraceSource.UNSET) { tagMap.put( - APPSEC_TAG.forType(Encoding.DATADOG).toString(), - APPSEC_ENABLED_TAG_VALUE.forType(Encoding.DATADOG).toString()); + TRACE_SOURCE_TAG.forType(Encoding.DATADOG).toString(), + TagValue.from(ProductTraceSource.getBitfieldHex(propagationTags.getTraceSource())) + .forType(Encoding.DATADOG) + .toString()); } if (propagationTags.getDebugPropagation() != null) { tagMap.put( @@ -158,7 +165,7 @@ protected static boolean validateTagValue(TagKey tagKey, TagValue tagValue) { return false; } else if (tagKey.equals(TRACE_ID_TAG) && !validateTraceId(tagValue)) { return false; - } else if (tagKey.equals(APPSEC_TAG) && !validateAppsecTagValue(tagValue)) { + } else if (tagKey.equals(TRACE_SOURCE_TAG) && !validateTraceSourceTagValue(tagValue)) { return false; } return true; @@ -222,8 +229,18 @@ private static boolean validateTraceId(TagValue value) { return true; } - private static boolean validateAppsecTagValue(TagValue value) { - return value.length() == 1 && (value.charAt(0) == '1' || value.charAt(0) == '0'); + private static boolean validateTraceSourceTagValue(TagValue value) { + // Ensure the string is not null and has a length between 2 and 8 + if (value == null || value.length() < 2 || value.length() > 8) { + return false; + } + for (int i = 0; i < value.length(); i++) { + // Ensure each character is a valid hex digit + if (!isHexDigitCaseInsensitive(value.charAt(i))) { + return false; + } + } + return true; } protected static boolean isDigit(char c) { @@ -233,4 +250,8 @@ protected static boolean isDigit(char c) { protected static boolean isHexDigit(char c) { return c >= 'a' && c <= 'f' || isDigit(c); } + + protected static boolean isHexDigitCaseInsensitive(char c) { + return isHexDigit(c) || c >= 'A' && c <= 'F'; + } } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/PTagsFactory.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/PTagsFactory.java index fe111d7ea50..942fa5b2821 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/PTagsFactory.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/PTagsFactory.java @@ -2,11 +2,11 @@ import static datadog.trace.core.propagation.PropagationTags.HeaderType.DATADOG; import static datadog.trace.core.propagation.PropagationTags.HeaderType.W3C; -import static datadog.trace.core.propagation.ptags.PTagsCodec.APPSEC_ENABLED_TAG_VALUE; -import static datadog.trace.core.propagation.ptags.PTagsCodec.APPSEC_TAG; import static datadog.trace.core.propagation.ptags.PTagsCodec.DECISION_MAKER_TAG; import static datadog.trace.core.propagation.ptags.PTagsCodec.TRACE_ID_TAG; +import static datadog.trace.core.propagation.ptags.PTagsCodec.TRACE_SOURCE_TAG; +import datadog.trace.api.ProductTraceSource; import datadog.trace.api.internal.util.LongStringUtils; import datadog.trace.api.sampling.PrioritySampling; import datadog.trace.api.sampling.SamplingMechanism; @@ -18,6 +18,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.Nonnull; public class PTagsFactory implements PropagationTags.Factory { @@ -47,7 +48,7 @@ PTagsCodec getDecoderEncoder(@Nonnull HeaderType headerType) { @Override public final PropagationTags empty() { - return createValid(null, null, null, false); + return createValid(null, null, null, ProductTraceSource.UNSET); } @Override @@ -59,9 +60,8 @@ PropagationTags createValid( List tagPairs, TagValue decisionMakerTagValue, TagValue traceIdTagValue, - boolean appsecPropagationEnabled) { - return new PTags( - this, tagPairs, decisionMakerTagValue, traceIdTagValue, appsecPropagationEnabled); + int productTraceSource) { + return new PTags(this, tagPairs, decisionMakerTagValue, traceIdTagValue, productTraceSource); } PropagationTags createInvalid(String error) { @@ -81,7 +81,7 @@ static class PTags extends PropagationTags { // extracted decision maker tag for easier updates private volatile TagValue decisionMakerTagValue; - private volatile boolean appsecPropagationEnabled; + private final AtomicInteger traceSource; private volatile String debugPropagation; // xDatadogTagsSize of the tagPairs, does not include the decision maker tag @@ -119,13 +119,13 @@ public PTags( List tagPairs, TagValue decisionMakerTagValue, TagValue traceIdTagValue, - boolean appsecPropagationEnabled) { + int traceSource) { this( factory, tagPairs, decisionMakerTagValue, traceIdTagValue, - appsecPropagationEnabled, + traceSource, PrioritySampling.UNSET, null, null); @@ -136,7 +136,7 @@ public PTags( List tagPairs, TagValue decisionMakerTagValue, TagValue traceIdTagValue, - boolean appsecPropagationEnabled, + int traceSource, int samplingPriority, CharSequence origin, CharSequence lastParentId) { @@ -145,7 +145,7 @@ public PTags( this.tagPairs = tagPairs; this.canChangeDecisionMaker = decisionMakerTagValue == null; this.decisionMakerTagValue = decisionMakerTagValue; - this.appsecPropagationEnabled = appsecPropagationEnabled; + this.traceSource = new AtomicInteger(traceSource); this.samplingPriority = samplingPriority; this.origin = origin; this.lastParentId = lastParentId; @@ -160,7 +160,16 @@ public PTags( } static PTags withError(PTagsFactory factory, String error) { - PTags pTags = new PTags(factory, null, null, null, false, PrioritySampling.UNSET, null, null); + PTags pTags = + new PTags( + factory, + null, + null, + null, + ProductTraceSource.UNSET, + PrioritySampling.UNSET, + null, + null); pTags.error = error; return pTags; } @@ -204,18 +213,26 @@ public void updateTraceSamplingPriority(int samplingPriority, int samplingMechan } @Override - public void updateAppsecPropagation(boolean enabled) { - if (appsecPropagationEnabled != enabled) { - // This should invalidate any cached w3c and datadog header - clearCachedHeader(DATADOG); - clearCachedHeader(W3C); - } - appsecPropagationEnabled = enabled; + public void addTraceSource(final int product) { + traceSource.updateAndGet( + currentValue -> { + // If the product is already marked, return the same value (no change) + if (ProductTraceSource.isProductMarked(currentValue, product)) { + return currentValue; + } + + // Invalidate cached headers (atomic context ensures correctness) + clearCachedHeader(DATADOG); + clearCachedHeader(W3C); + + // Set the bit for the given product + return ProductTraceSource.updateProduct(currentValue, product); + }); } @Override - public boolean isAppsecPropagationEnabled() { - return appsecPropagationEnabled; + public int getTraceSource() { + return traceSource.get(); } @Override @@ -353,8 +370,13 @@ int getXDatadogTagsSize() { size = PTagsCodec.calcXDatadogTagsSize(getTagPairs()); size = PTagsCodec.calcXDatadogTagsSize(size, DECISION_MAKER_TAG, decisionMakerTagValue); size = PTagsCodec.calcXDatadogTagsSize(size, TRACE_ID_TAG, traceIdHighOrderBitsHexTagValue); - if (appsecPropagationEnabled) { - size = PTagsCodec.calcXDatadogTagsSize(size, APPSEC_TAG, APPSEC_ENABLED_TAG_VALUE); + int currentProductTraceSource = traceSource.get(); + if (currentProductTraceSource != ProductTraceSource.UNSET) { + size = + PTagsCodec.calcXDatadogTagsSize( + size, + TRACE_SOURCE_TAG, + TagValue.from(ProductTraceSource.getBitfieldHex(currentProductTraceSource))); } xDatadogTagsSize = size; } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/W3CPTagsCodec.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/W3CPTagsCodec.java index df020a9e53e..3b99aa1aa62 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/W3CPTagsCodec.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/ptags/W3CPTagsCodec.java @@ -2,6 +2,7 @@ import static datadog.trace.api.internal.util.LongStringUtils.toHexStringPadded; +import datadog.trace.api.ProductTraceSource; import datadog.trace.api.sampling.PrioritySampling; import datadog.trace.core.propagation.PropagationTags; import datadog.trace.core.propagation.ptags.PTagsFactory.PTags; @@ -93,7 +94,7 @@ PropagationTags fromHeaderValue(PTagsFactory tagsFactory, String value) { CharSequence origin = null; TagValue decisionMakerTagValue = null; TagValue traceIdTagValue = null; - boolean appsecPropagationEnabled = false; + int traceSource = ProductTraceSource.UNSET; int maxUnknownSize = 0; CharSequence lastParentId = null; while (tagPos < ddMemberValueEnd) { @@ -147,8 +148,8 @@ PropagationTags fromHeaderValue(PTagsFactory tagsFactory, String value) { decisionMakerTagValue = tagValue; } else if (tagKey.equals(TRACE_ID_TAG)) { traceIdTagValue = tagValue; - } else if (tagKey.equals(APPSEC_TAG)) { - appsecPropagationEnabled = tagValue.charAt(0) == '1'; + } else if (tagKey.equals(TRACE_SOURCE_TAG)) { + traceSource = ProductTraceSource.parseBitfieldHex(tagValue.toString()); } else { if (tagPairs == null) { // This is roughly the size of a two element linked list but can hold six @@ -182,7 +183,7 @@ PropagationTags fromHeaderValue(PTagsFactory tagsFactory, String value) { tagPairs, decisionMakerTagValue, traceIdTagValue, - appsecPropagationEnabled, + traceSource, samplingPriority, origin, value, @@ -707,7 +708,7 @@ private static W3CPTags empty( null, null, null, - false, + ProductTraceSource.UNSET, PrioritySampling.UNSET, null, original, @@ -739,7 +740,7 @@ public W3CPTags( List tagPairs, TagValue decisionMakerTagValue, TagValue traceIdTagValue, - boolean appsecPropagationEnabled, + int traceSource, int samplingPriority, CharSequence origin, String original, @@ -753,7 +754,7 @@ public W3CPTags( tagPairs, decisionMakerTagValue, traceIdTagValue, - appsecPropagationEnabled, + traceSource, samplingPriority, origin, lastParentId); diff --git a/dd-trace-core/src/main/java/datadog/trace/core/taginterceptor/TagInterceptor.java b/dd-trace-core/src/main/java/datadog/trace/core/taginterceptor/TagInterceptor.java index 56ae6da4c75..931eca80721 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/taginterceptor/TagInterceptor.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/taginterceptor/TagInterceptor.java @@ -112,9 +112,12 @@ public boolean interceptTag(DDSpanContext span, String tag, Object value) { return false; case Tags.SAMPLING_PRIORITY: return interceptSamplingPriority(span, value); - case Tags.PROPAGATED_APPSEC: - span.updateAppsecPropagation(asBoolean(value)); - return true; + case Tags.PROPAGATED_TRACE_SOURCE: + if (value instanceof Integer) { + span.addPropagatedTraceSource((Integer) value); + return true; + } + return false; case Tags.PROPAGATED_DEBUG: span.updateDebugPropagation(String.valueOf(value)); return true; diff --git a/dd-trace-core/src/test/groovy/datadog/trace/common/sampling/SamplerTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/common/sampling/SamplerTest.groovy index f231d62a6a5..5591b118e5d 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/common/sampling/SamplerTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/common/sampling/SamplerTest.groovy @@ -5,9 +5,10 @@ import datadog.trace.test.util.DDSpecification class SamplerTest extends DDSpecification{ - void "test that TimeSampler is selected when experimentalAppSecStandalone is enabled"() { + void "test that AsmStandaloneSampler is selected when apm tracing disabled and appsec enabled is enabled"() { setup: - System.setProperty("dd.experimental.appsec.standalone.enabled", "true") + System.setProperty("dd.apm.tracing.enabled", "false") + System.setProperty("dd.appsec.enabled", "true") Config config = new Config() when: @@ -16,4 +17,40 @@ class SamplerTest extends DDSpecification{ then: sampler instanceof AsmStandaloneSampler } + + void "test that AsmStandaloneSampler is selected when apm tracing disabled and iast enabled is enabled"() { + setup: + System.setProperty("dd.apm.tracing.enabled", "false") + System.setProperty("dd.iast.enabled", "true") + Config config = new Config() + + when: + Sampler sampler = Sampler.Builder.forConfig(config, null) + + then: + sampler instanceof AsmStandaloneSampler + } + + void "test that AsmStandaloneSampler is not selected when apm tracing and asm not enabled"() { + setup: + System.setProperty("dd.apm.tracing.enabled", "false") + Config config = new Config() + + when: + Sampler sampler = Sampler.Builder.forConfig(config, null) + + then: + !(sampler instanceof AsmStandaloneSampler) + } + + void "test that AsmStandaloneSampler is not selected when apm tracing and asm not enabled"() { + setup: + Config config = new Config() + + when: + Sampler sampler = Sampler.Builder.forConfig(config, null) + + then: + !(sampler instanceof AsmStandaloneSampler) + } } diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/propagation/DatadogPropagationTagsTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/propagation/DatadogPropagationTagsTest.groovy index caccaf98b4f..60a56900a36 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/propagation/DatadogPropagationTagsTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/propagation/DatadogPropagationTagsTest.groovy @@ -1,6 +1,7 @@ package datadog.trace.core.propagation import datadog.trace.api.Config +import datadog.trace.api.ProductTraceSource import datadog.trace.core.test.DDCoreSpecification import static datadog.trace.api.sampling.PrioritySampling.* @@ -72,9 +73,9 @@ class DatadogPropagationTagsTest extends DDCoreSpecification { "_dd.p.tid=123456789ABCDEF0" | null | ["_dd.propagation_error": "malformed_tid 123456789ABCDEF0"] // invalid tid tag value: upper-case characters "_dd.p.tid=123456789abcdefg" | null | ["_dd.propagation_error": "malformed_tid 123456789abcdefg"] // invalid tid tag value: non-hexadecimal characters "_dd.p.tid=-123456789abcdef" | null | ["_dd.propagation_error": "malformed_tid -123456789abcdef"] // invalid tid tag value: non-hexadecimal characters - "_dd.p.appsec=1" | "_dd.p.appsec=1" | ["_dd.p.appsec": "1"] - "_dd.p.appsec=0" | null | [:] - "_dd.p.appsec=foo" | null | ["_dd.propagation_error":"decoding_error"] + "_dd.p.ts=02" | "_dd.p.ts=02" | ["_dd.p.ts": "02"] + "_dd.p.ts=00" | null | [:] + "_dd.p.ts=foo" | null | ["_dd.propagation_error": "decoding_error"] } def "datadog propagation tags should translate to w3c tags #headerValue"() { @@ -138,7 +139,7 @@ class DatadogPropagationTagsTest extends DDCoreSpecification { ",_dd.p.dm=Value" | SAMPLER_KEEP | AGENT_RATE | "_dd.p.dm=-1" | ["_dd.propagation_error": "decoding_error", "_dd.p.dm": "-1"] } - def "update propagation tags appsec propagation #originalTagSet"() { + def "update propagation tags trace source propagation #originalTagSet"() { setup: def config = Mock(Config) config.getxDatadogTagsMaxLength() >> 512 @@ -146,20 +147,26 @@ class DatadogPropagationTagsTest extends DDCoreSpecification { def propagationTags = propagationTagsFactory.fromHeaderValue(PropagationTags.HeaderType.DATADOG, originalTagSet) when: - propagationTags.updateAppsecPropagation(enabled) + propagationTags.addTraceSource(product) then: propagationTags.headerValue(PropagationTags.HeaderType.DATADOG) == expectedHeaderValue propagationTags.createTagMap() == tags where: - originalTagSet | enabled | expectedHeaderValue | tags + originalTagSet | product | expectedHeaderValue | tags // keep the existing dm tag as is - "_dd.p.appsec=1" | true | "_dd.p.appsec=1" | ["_dd.p.appsec": "1"] - "_dd.p.appsec=0" | false | null | [:] - "" | false | null | [:] + "" | ProductTraceSource.ASM | "_dd.p.ts=02" | ["_dd.p.ts": "02"] + "_dd.p.ts=00" | ProductTraceSource.ASM | "_dd.p.ts=02" | ["_dd.p.ts": "02"] + "_dd.p.ts=FFC00000" | ProductTraceSource.ASM | "_dd.p.ts=02" | ["_dd.p.ts": "02"] + "_dd.p.ts=02" | ProductTraceSource.DBM | "_dd.p.ts=12" | ["_dd.p.ts": "12"] //Invalid input - "_dd.p.appsec=foo" | false | null | ["_dd.propagation_error": "decoding_error"] + "_dd.p.ts=" | ProductTraceSource.UNSET | null | ["_dd.propagation_error": "decoding_error"] + "_dd.p.ts=0" | ProductTraceSource.UNSET | null | ["_dd.propagation_error": "decoding_error"] + "_dd.p.ts=0G" | ProductTraceSource.UNSET | null | ["_dd.propagation_error": "decoding_error"] + "_dd.p.ts=GG" | ProductTraceSource.UNSET | null | ["_dd.propagation_error": "decoding_error"] + "_dd.p.ts=foo" | ProductTraceSource.UNSET | null | ["_dd.propagation_error": "decoding_error"] + "_dd.p.ts=000000002" | ProductTraceSource.UNSET | null | ["_dd.propagation_error": "decoding_error"] } def extractionLimitExceeded() { diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/propagation/TracingPropagatorTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/propagation/TracingPropagatorTest.groovy index 7c26cbc7e16..20a6ff8942d 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/propagation/TracingPropagatorTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/propagation/TracingPropagatorTest.groovy @@ -157,9 +157,9 @@ class TracingPropagatorTest extends DDCoreSpecification { tracer.close() } - def 'test ASM standalone billing propagator stop propagation'() { + def 'test APM Tracing disabled propagator stop propagation'() { setup: - injectSysConfig('experimental.appsec.standalone.enabled', standaloneAsmEnabled.toString()) + injectSysConfig('apm.tracing.enabled', apmTracingEnabled.toString()) def tracer = tracerBuilder().build() def span = tracer.buildSpan('test', 'operation').start() def setter = Mock(CarrierSetter) @@ -169,10 +169,10 @@ class TracingPropagatorTest extends DDCoreSpecification { Propagators.defaultPropagator().inject(span, carrier, setter) then: - if (standaloneAsmEnabled) { - 0 * setter.set(_, _, _) - } else { + if (apmTracingEnabled) { (1.._) * setter.set(_, _, _) + } else { + 0 * setter.set(_, _, _) } cleanup: @@ -180,6 +180,6 @@ class TracingPropagatorTest extends DDCoreSpecification { tracer.close() where: - standaloneAsmEnabled << [true, false] + apmTracingEnabled << [true, false] } } diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/propagation/W3CPropagationTagsTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/propagation/W3CPropagationTagsTest.groovy index 3bd0ddfe7b1..6f6540249cb 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/propagation/W3CPropagationTagsTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/propagation/W3CPropagationTagsTest.groovy @@ -1,6 +1,7 @@ package datadog.trace.core.propagation import datadog.trace.api.Config +import datadog.trace.api.ProductTraceSource import datadog.trace.api.sampling.PrioritySampling import datadog.trace.api.sampling.SamplingMechanism import datadog.trace.core.test.DDCoreSpecification @@ -237,9 +238,9 @@ class W3CPropagationTagsTest extends DDCoreSpecification { null | null | [:] '' | null | [:] 'dd=s:0;t.dm:934086a686-4' | 'dd=s:0;t.dm:934086a686-4' | ['_dd.p.dm': '934086a686-4'] - 'dd=s:0;t.appsec:1' | 'dd=s:0;t.appsec:1' | ['_dd.p.appsec': '1'] - 'dd=s:0;t.appsec:0' | 'dd=s:0' | [:] - 'dd=s:0;t.dm:934086a686-4;t.appsec:1' | 'dd=s:0;t.dm:934086a686-4;t.appsec:1' | ['_dd.p.dm': '934086a686-4', '_dd.p.appsec': '1'] + 'dd=s:0;t.ts:02' | 'dd=s:0;t.ts:02' | ['_dd.p.ts': '02'] + 'dd=s:0;t.ts:00' | 'dd=s:0' | [:] + 'dd=s:0;t.dm:934086a686-4;t.ts:02' | 'dd=s:0;t.dm:934086a686-4;t.ts:02' | ['_dd.p.dm': '934086a686-4', '_dd.p.ts': '02'] 'other=whatever,dd=s:0;t.dm:934086a686-4' | 'dd=s:0;t.dm:934086a686-4,other=whatever' | ['_dd.p.dm': '934086a686-4'] 'dd=s:0;t.dm:934086a687-3,other=whatever' | 'dd=s:0;t.dm:934086a687-3,other=whatever' | ['_dd.p.dm': '934086a687-3'] 'some=thing,dd=s:0;t.dm:934086a687-3,other=whatever' | 'dd=s:0;t.dm:934086a687-3,some=thing,other=whatever' | ['_dd.p.dm': '934086a687-3'] @@ -278,14 +279,15 @@ class W3CPropagationTagsTest extends DDCoreSpecification { propagationTags.createTagMap() == tags where: - headerValue | expectedHeaderValue | tags - 'dd=s:0;t.dm:934086a686-4' | '_dd.p.dm=934086a686-4' | ['_dd.p.dm': '934086a686-4'] - 'other=whatever,dd=s:0;t.dm:934086a686-4;t.f:w00t~~' | '_dd.p.dm=934086a686-4,_dd.p.f=w00t==' | ['_dd.p.dm': '934086a686-4', '_dd.p.f': 'w00t=='] - 'dd=s:0;t.appsec:1' | '_dd.p.appsec=1' | ['_dd.p.appsec': '1'] - 'dd=s:0;t.appsec:0' | null | [:] - 'dd=s:0;t.appsec:invalid' | null | [:] - 'other=whatever,dd=s:0;t.dm:934086a686-4;t.f:w00t~~;t.appsec:1' | '_dd.p.dm=934086a686-4,_dd.p.appsec=1,_dd.p.f=w00t==' | ['_dd.p.dm': '934086a686-4', '_dd.p.f': 'w00t==', '_dd.p.appsec': '1'] - 'some=thing,other=whatever' | null | [:] + headerValue | expectedHeaderValue | tags + 'dd=s:0;t.dm:934086a686-4' | '_dd.p.dm=934086a686-4' | ['_dd.p.dm': '934086a686-4'] + 'other=whatever,dd=s:0;t.dm:934086a686-4;t.f:w00t~~' | '_dd.p.dm=934086a686-4,_dd.p.f=w00t==' | ['_dd.p.dm': '934086a686-4', '_dd.p.f': 'w00t=='] + 'dd=s:0;t.ts:02' | '_dd.p.ts=02' | ['_dd.p.ts': '02'] + 'dd=s:0;t.ts:00' | null | [:] + 'dd=s:0;t.ts:0' | null | [:] + 'dd=s:0;t.ts:invalid' | null | [:] + 'other=whatever,dd=s:0;t.dm:934086a686-4;t.f:w00t~~;t.ts:02' | '_dd.p.dm=934086a686-4,_dd.p.ts=02,_dd.p.f=w00t==' | ['_dd.p.dm': '934086a686-4', '_dd.p.f': 'w00t==', '_dd.p.ts': '02'] + 'some=thing,other=whatever' | null | [:] } def "propagation tags should be updated by sampling and origin #headerValue #priority #mechanism #origin"() { @@ -309,7 +311,7 @@ class W3CPropagationTagsTest extends DDCoreSpecification { propagationTags.createTagMap() == tags where: - headerValue | priority | mechanism | origin | expectedHeaderValue | tags + headerValue | priority | mechanism | origin | expectedHeaderValue | tags 'dd=s:0;o:some;t.dm:934086a686-4' | PrioritySampling.SAMPLER_KEEP | SamplingMechanism.DEFAULT | "other" | 'dd=s:0;o:other;t.dm:934086a686-4' | ['_dd.p.dm': '934086a686-4'] 'dd=s:0;o:some;x:unknown' | PrioritySampling.USER_KEEP | SamplingMechanism.LOCAL_USER_RULE | "same" | 'dd=s:2;o:same;t.dm:-3;x:unknown' | ['_dd.p.dm': '-3'] 'dd=s:0;o:some;x:unknown' | PrioritySampling.USER_DROP | SamplingMechanism.MANUAL | null | 'dd=s:-1;x:unknown' | [:] @@ -317,7 +319,7 @@ class W3CPropagationTagsTest extends DDCoreSpecification { 'dd=s:1;o:some;t.dm:934086a686-4' | PrioritySampling.SAMPLER_DROP | SamplingMechanism.EXTERNAL_OVERRIDE | "other" | 'dd=s:0;o:other' | [:] } - def "propagation tags should be updated by appsec propagation #appsec"() { + def "propagation tags should be updated by product trace source propagation #product"() { setup: def config = Mock(Config) config.getxDatadogTagsMaxLength() >> 512 @@ -330,17 +332,18 @@ class W3CPropagationTagsTest extends DDCoreSpecification { propagationTags.headerValue(HeaderType.W3C) != expectedHeaderValue when: - propagationTags.updateAppsecPropagation(appsec) + propagationTags.addTraceSource(product) then: propagationTags.headerValue(HeaderType.W3C) == expectedHeaderValue propagationTags.createTagMap() == tags where: - headerValue | appsec | expectedHeaderValue | tags - 'dd=t.appsec:1;x:unknown' | false | 'dd=x:unknown' | [:] - 'dd=x:unknown' | true | 'dd=t.appsec:1;x:unknown' | ['_dd.p.appsec': '1'] - 'dd=t.appsec:0;x:unknown' | true | 'dd=t.appsec:1;x:unknown' | ['_dd.p.appsec': '1'] + headerValue | product | expectedHeaderValue | tags + 'dd=x:unknown' | ProductTraceSource.ASM | 'dd=t.ts:02;x:unknown' | ['_dd.p.ts': '02'] + 'dd=t.ts:02;x:unknown' | ProductTraceSource.DBM | 'dd=t.ts:12;x:unknown' | ['_dd.p.ts': '12'] + "dd=t.ts:00" | ProductTraceSource.ASM | 'dd=t.ts:02' | ["_dd.p.ts": "02"] + "dd=t.ts:FFC00000" | ProductTraceSource.ASM | 'dd=t.ts:02' | ["_dd.p.ts": "02"] } static private String toLcAlpha(String cs) { diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/taginterceptor/TagInterceptorTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/taginterceptor/TagInterceptorTest.groovy index 9156ce067bb..075ac57a188 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/taginterceptor/TagInterceptorTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/taginterceptor/TagInterceptorTest.groovy @@ -3,6 +3,7 @@ package datadog.trace.core.taginterceptor import static datadog.trace.api.ConfigDefaults.DEFAULT_SERVICE_NAME import static datadog.trace.api.ConfigDefaults.DEFAULT_SERVLET_ROOT_CONTEXT_SERVICE_NAME import static datadog.trace.api.DDTags.ANALYTICS_SAMPLE_RATE +import datadog.trace.api.ProductTraceSource import static datadog.trace.api.config.TracerConfig.SPLIT_BY_TAGS import datadog.trace.api.DDSpanTypes @@ -730,7 +731,7 @@ class TagInterceptorTest extends DDCoreSpecification { "test" | "test" } - void "When intercepts appsec propagation tag addAppsecPropagationTag is called"() { + void "When intercepts product trace source propagation tag updatePropagatedTraceSource is called"() { setup: final ruleFlags = Mock(RuleFlags) ruleFlags.isEnabled(_) >> true @@ -738,9 +739,9 @@ class TagInterceptorTest extends DDCoreSpecification { final context = Mock(DDSpanContext) when: - interceptor.interceptTag(context, Tags.PROPAGATED_APPSEC, true) + interceptor.interceptTag(context, Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM) then: - 1 * context.updateAppsecPropagation(true) + 1 * context.addPropagatedTraceSource(ProductTraceSource.ASM) } } diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index c6c4258b3be..e6441d3cbdf 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -287,7 +287,6 @@ public static String getHostName() { private final boolean appSecStackTraceEnabled; private final int appSecMaxStackTraces; private final int appSecMaxStackTraceDepth; - private final boolean appSecStandaloneEnabled; private final boolean apiSecurityEnabled; private final float apiSecurityRequestSampleRate; @@ -554,6 +553,8 @@ public static String getHostName() { private final long dependecyResolutionPeriodMillis; + private final boolean apmTracingEnabled; + // Read order: System Properties -> Env Variables, [-> properties file], [-> default value] private Config() { this(ConfigProvider.createDefault()); @@ -1292,7 +1293,6 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment()) configProvider.getStringNotEmpty(APPSEC_AUTO_USER_INSTRUMENTATION_MODE, null), configProvider.getStringNotEmpty(APPSEC_AUTOMATED_USER_EVENTS_TRACKING, null)); appSecScaEnabled = configProvider.getBoolean(APPSEC_SCA_ENABLED); - appSecStandaloneEnabled = configProvider.getBoolean(APPSEC_STANDALONE_ENABLED, false); appSecRaspEnabled = configProvider.getBoolean(APPSEC_RASP_ENABLED, DEFAULT_APPSEC_RASP_ENABLED); appSecStackTraceEnabled = configProvider.getBoolean( @@ -1915,6 +1915,8 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment()) "AppSec SCA is enabled but telemetry is disabled. AppSec SCA will not work."); } + this.apmTracingEnabled = configProvider.getBoolean(GeneralConfig.APM_TRACING_ENABLED, true); + log.debug("New instance: {}", this); } @@ -2333,7 +2335,7 @@ public boolean isPerfMetricsEnabled() { public boolean isTracerMetricsEnabled() { // When ASM Standalone Billing is enabled metrics should be disabled - return tracerMetricsEnabled && !isAppSecStandaloneEnabled(); + return tracerMetricsEnabled && isApmTracingEnabled(); } public boolean isTracerMetricsBufferingEnabled() { @@ -3445,6 +3447,10 @@ public String getDataJobsCommandPattern() { return dataJobsCommandPattern; } + public boolean isApmTracingEnabled() { + return apmTracingEnabled; + } + /** @return A map of tags to be applied only to the local application root span. */ public Map getLocalRootSpanTags() { final Map runtimeTags = getRuntimeTags(); @@ -3453,7 +3459,7 @@ public Map getLocalRootSpanTags() { result.put(LANGUAGE_TAG_KEY, LANGUAGE_TAG_VALUE); result.put(SCHEMA_VERSION_TAG_KEY, SpanNaming.instance().version()); result.put(DDTags.PROFILING_ENABLED, isProfilingEnabled() ? 1 : 0); - if (isAppSecStandaloneEnabled()) { + if (!isApmTracingEnabled()) { result.put(APM_ENABLED, 0); } @@ -3972,10 +3978,6 @@ public Boolean getAppSecScaEnabled() { return appSecScaEnabled; } - public boolean isAppSecStandaloneEnabled() { - return appSecStandaloneEnabled; - } - public boolean isAppSecRaspEnabled() { return appSecRaspEnabled; } @@ -4684,8 +4686,8 @@ public String toString() { + dataJobsEnabled + ", dataJobsCommandPattern=" + dataJobsCommandPattern - + ", appSecStandaloneEnabled=" - + appSecStandaloneEnabled + + ", apmTracingEnabled=" + + apmTracingEnabled + ", cloudRequestPayloadTagging=" + cloudRequestPayloadTagging + ", cloudResponsePayloadTagging=" diff --git a/internal-api/src/main/java/datadog/trace/api/ProductTraceSource.java b/internal-api/src/main/java/datadog/trace/api/ProductTraceSource.java new file mode 100644 index 00000000000..792829dde3a --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/api/ProductTraceSource.java @@ -0,0 +1,60 @@ +package datadog.trace.api; + +/** + * Represents a bitfield-based trace source for tracking product propagation tags. + * + *

The bitfield is encoded as an **8-bit hexadecimal mask** (ranging from `00` to `FF`), where + * each bit corresponds to a specific product. This class provides utility methods for updating, + * checking, and parsing these product bitfields. + * + *

    + *
  • MUST use a two-character, case-insensitive hexadecimal string (e.g., "00" to "FF"). + *
  • MUST support parsing masks of at least 32 bits to ensure forward compatibility. + *
  • Each bit corresponds to a specific product: + *
+ */ +public class ProductTraceSource { + + public static final int UNSET = 0; + + public static final int APM = 0x01; + public static final int ASM = 0x02; + public static final int DSM = 0x04; + public static final int DJM = 0x08; + public static final int DBM = 0x10; + + /** Updates the bitfield by setting the bit corresponding to a specific product. */ + public static int updateProduct(int bitfield, int product) { + return bitfield |= product; // Set the bit for the given product + } + + /** Checks if the bitfield is marked for a specific product. */ + public static boolean isProductMarked(final int bitfield, int product) { + return (bitfield & product) != 0; // Check if the bit is set + } + + /** + * Converts the current bitfield to a two-character hexadecimal string. + * + *

This method ensures the output follows the **00 to FF** format, padding with leading zeros + * if necessary. + */ + public static String getBitfieldHex(final int bitfield) { + String hex = Integer.toHexString(bitfield & 0xFF); + return hex.length() == 1 ? "0" + hex : hex; // Ensure two characters + } + + /** + * Parses a hexadecimal string back into an integer bitfield. + * + *

This method allows for **at least 32-bit parsing**, ensuring forward compatibility with + * potential future expansions. + */ + public static int parseBitfieldHex(final String hexString) { + if (hexString == null || hexString.isEmpty()) { + return 0; // Return 0 if the string is empty + } + // Need to support unsigned parsing + return (int) Long.parseUnsignedLong(hexString, 16); // Parse the string as a base-16 number + } +} diff --git a/internal-api/src/main/java/datadog/trace/api/sampling/SamplingMechanism.java b/internal-api/src/main/java/datadog/trace/api/sampling/SamplingMechanism.java index 0c71c9968ab..b21855bdb3e 100644 --- a/internal-api/src/main/java/datadog/trace/api/sampling/SamplingMechanism.java +++ b/internal-api/src/main/java/datadog/trace/api/sampling/SamplingMechanism.java @@ -69,7 +69,7 @@ public static boolean validateWithSamplingPriority(int mechanism, int priority) * @return */ public static boolean canAvoidSamplingPriorityLock(int priority, int mechanism) { - return Config.get().isAppSecStandaloneEnabled() && mechanism == SamplingMechanism.APPSEC; + return !Config.get().isApmTracingEnabled() && mechanism == SamplingMechanism.APPSEC; } private SamplingMechanism() {} diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/Tags.java b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/Tags.java index 5c15a92f206..587d70bb93f 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/Tags.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/Tags.java @@ -146,6 +146,6 @@ public class Tags { /** ASM force tracer to keep the trace */ public static final String ASM_KEEP = "asm.keep"; - public static final String PROPAGATED_APPSEC = "_dd.p.appsec"; + public static final String PROPAGATED_TRACE_SOURCE = "_dd.p.ts"; public static final String PROPAGATED_DEBUG = "_dd.p.debug"; } diff --git a/internal-api/src/test/groovy/datadog/trace/api/ProductTraceSourceTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ProductTraceSourceTest.groovy new file mode 100644 index 00000000000..bc376154217 --- /dev/null +++ b/internal-api/src/test/groovy/datadog/trace/api/ProductTraceSourceTest.groovy @@ -0,0 +1,60 @@ +package datadog.trace.api + +import datadog.trace.test.util.DDSpecification + +class ProductTraceSourceTest extends DDSpecification { + + void 'test updateProduct'(){ + when: + final result = ProductTraceSource.updateProduct(init, newProduct) + + then: + result == expected + + where: + init | newProduct | expected + ProductTraceSource.UNSET | ProductTraceSource.ASM | ProductTraceSource.ASM + ProductTraceSource.ASM | ProductTraceSource.DSM | 6 + } + + void 'test isProductMarked'(){ + when: + final result = ProductTraceSource.isProductMarked(value, product) + + then: + result == expected + + where: + value | product | expected + ProductTraceSource.ASM | ProductTraceSource.ASM | true + ProductTraceSource.DSM | ProductTraceSource.ASM | false + } + + void 'test getBitfieldHex'(){ + when: + final result = ProductTraceSource.getBitfieldHex(value) + + then: + result == expected + + where: + value | expected + ProductTraceSource.UNSET | "00" + ProductTraceSource.ASM | "02" + } + + void 'test parseBitfieldHex'(){ + when: + final result = ProductTraceSource.parseBitfieldHex(hex) + + then: + result == expected + + where: + hex | expected + "00" | ProductTraceSource.UNSET + null | ProductTraceSource.UNSET + "" | ProductTraceSource.UNSET + "02" | ProductTraceSource.ASM + } +} diff --git a/internal-api/src/test/groovy/datadog/trace/api/sampling/SamplingMechanismTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/sampling/SamplingMechanismTest.groovy index 60c3634d0e6..4a4890435c1 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/sampling/SamplingMechanismTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/sampling/SamplingMechanismTest.groovy @@ -98,7 +98,7 @@ class SamplingMechanismTest extends DDSpecification { void 'Test canAvoidSamplingPriorityLock'(){ setup: - injectSysConfig("dd.experimental.appsec.standalone.enabled", "true") + injectSysConfig("dd.apm.tracing.enabled", "false") expect: canAvoidSamplingPriorityLock(priority, mechanism) == valid diff --git a/settings.gradle b/settings.gradle index f6082cc6b63..54bdd9e80dc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -92,8 +92,8 @@ include ':utils:time-utils' include ':utils:version-utils' // smoke tests +include ':dd-smoke-tests:apm-tracing-disabled' include ':dd-smoke-tests:armeria-grpc' -include ':dd-smoke-tests:asm-standalone-billing' include ':dd-smoke-tests:backend-mock' include ':dd-smoke-tests:cli' include ':dd-smoke-tests:crashtracking'