Skip to content

Commit be93bfa

Browse files
committed
Create activation origin config for telemetry
Signed-off-by: sezen.leblay <[email protected]>
1 parent 46d0949 commit be93bfa

File tree

4 files changed

+95
-10
lines changed

4 files changed

+95
-10
lines changed

dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/AppSecConfigServiceImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static datadog.remoteconfig.Capabilities.CAPABILITY_ASM_TRUSTED_IPS;
2222
import static datadog.remoteconfig.Capabilities.CAPABILITY_ASM_USER_BLOCKING;
2323
import static datadog.remoteconfig.Capabilities.CAPABILITY_ENDPOINT_FINGERPRINT;
24+
import static datadog.trace.api.config.AppSecConfig.APPSEC_ENABLED;
2425

2526
import com.datadog.appsec.AppSecModule;
2627
import com.datadog.appsec.AppSecSystem;
@@ -45,6 +46,8 @@
4546
import datadog.remoteconfig.state.ConfigKey;
4647
import datadog.remoteconfig.state.ProductListener;
4748
import datadog.trace.api.Config;
49+
import datadog.trace.api.ConfigCollector;
50+
import datadog.trace.api.ConfigOrigin;
4851
import datadog.trace.api.ProductActivation;
4952
import datadog.trace.api.UserIdCollectionMode;
5053
import datadog.trace.api.telemetry.LogCollector;
@@ -522,6 +525,13 @@ private void setAppSecActivation(final AppSecFeatures.Asm asm) {
522525
newState = tracerConfig.getAppSecActivation() == ProductActivation.FULLY_ENABLED;
523526
} else {
524527
newState = asm.enabled;
528+
if (asm.enabled) {
529+
// Report AppSec activation change via telemetry when enabled via remote config
530+
ConfigCollector.get().put(APPSEC_ENABLED, true, ConfigOrigin.REMOTE);
531+
} else {
532+
// Report AppSec activation change via telemetry when disabled via remote config
533+
ConfigCollector.get().put(APPSEC_ENABLED, false, ConfigOrigin.REMOTE);
534+
}
525535
}
526536
if (AppSecSystem.isActive() != newState) {
527537
log.info("AppSec {} (runtime)", newState ? "enabled" : "disabled");

dd-smoke-tests/dynamic-config/src/main/java/datadog/smoketest/dynamicconfig/ServiceMappingApplication.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,37 @@ public static void main(String[] args) throws InterruptedException {
1717
Tracer tracer = GlobalTracer.get();
1818

1919
long startTime = System.nanoTime();
20+
boolean initialMappingObserved = false;
21+
boolean updatedMappingObserved = false;
2022

2123
while (System.nanoTime() - startTime < TIMEOUT_IN_NANOS) {
2224
Span span = tracer.buildSpan("someOperation").start();
2325
span.setTag(DDTags.SERVICE_NAME, ORIGINAL_SERVICE_NAME);
2426
String serviceName = ((MutableSpan) span).getServiceName();
2527

26-
if (serviceName.equals(MAPPED_SERVICE_NAME)) {
27-
System.out.println("Service mapping updated to dynamic value");
28-
System.exit(0);
28+
if (!initialMappingObserved && serviceName.equals(MAPPED_SERVICE_NAME)) {
29+
System.out.println("Initial service mapping updated to dynamic value");
30+
initialMappingObserved = true;
31+
}
32+
33+
// Wait for a second mapping (simulate a new config pushed after startup)
34+
if (initialMappingObserved && !updatedMappingObserved && serviceName.equals("baz")) {
35+
System.out.println("Updated service mapping applied");
36+
updatedMappingObserved = true;
37+
break;
2938
}
3039

3140
Thread.sleep(500);
3241
}
3342

34-
System.out.println("Service mapping never updated");
35-
System.exit(1);
43+
if (initialMappingObserved && updatedMappingObserved) {
44+
System.exit(0);
45+
} else if (initialMappingObserved) {
46+
System.out.println("Only initial mapping observed");
47+
System.exit(2);
48+
} else {
49+
System.out.println("Service mapping never updated");
50+
System.exit(1);
51+
}
3652
}
3753
}

dd-smoke-tests/dynamic-config/src/test/groovy/datadog/smoketest/DynamicServiceMappingSmokeTest.groovy

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package datadog.smoketest
22

33
import datadog.smoketest.dynamicconfig.ServiceMappingApplication
4-
54
import static java.util.concurrent.TimeUnit.SECONDS
65

76
class DynamicServiceMappingSmokeTest extends AbstractSmokeTest {
@@ -21,11 +20,13 @@ class DynamicServiceMappingSmokeTest extends AbstractSmokeTest {
2120

2221
ProcessBuilder processBuilder = new ProcessBuilder(command)
2322
processBuilder.directory(new File(buildDirectory))
23+
return processBuilder
2424
}
2525

26-
def "Updated service mapping observed"() {
27-
when:
28-
def newConfig = """
26+
@Override
27+
def setup() {
28+
// Set the initial remote configuration before the application starts
29+
def initialConfig = """
2930
{
3031
"lib_config": {
3132
"tracing_service_mapping": [{
@@ -35,11 +36,64 @@ class DynamicServiceMappingSmokeTest extends AbstractSmokeTest {
3536
}
3637
}
3738
""" as String
39+
setRemoteConfig("datadog/2/APM_TRACING/config_overrides/config", initialConfig)
40+
}
3841

39-
setRemoteConfig("datadog/2/APM_TRACING/config_overrides/config", newConfig)
42+
def "Service mapping updates are observed and reported via telemetry"() {
43+
when:
44+
// Wait for the app to start and apply the initial mapping
45+
assert !testedProcess.waitFor(5, SECONDS) // app should still be running
46+
47+
// Set the updated mapping after startup
48+
def updatedConfig = """
49+
{
50+
"lib_config": {
51+
"tracing_service_mapping": [{
52+
"from_key": "${ServiceMappingApplication.ORIGINAL_SERVICE_NAME}",
53+
"to_name": "baz"
54+
}]
55+
}
56+
}
57+
""" as String
58+
setRemoteConfig("datadog/2/APM_TRACING/config_overrides/config", updatedConfig)
4059

4160
then:
61+
// Wait for the process to exit (should be 0 if both mappings observed)
4262
assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS)
4363
assert testedProcess.exitValue() == 0
64+
65+
// Debug: Print all received telemetry messages
66+
println "=== All received telemetry messages ==="
67+
telemetryFlatMessages.each { msg ->
68+
println "Telemetry: ${msg.request_type} - ${msg.payload?.configuration?.size() ?: 0} configs"
69+
if (msg.payload?.configuration) {
70+
msg.payload.configuration.each { config ->
71+
if (config.name?.contains("service") || config.name?.contains("mapping")) {
72+
println " Config: ${config.name} = ${config.value} (origin: ${config.origin})"
73+
}
74+
}
75+
}
76+
}
77+
println "=== End telemetry messages ==="
78+
79+
// Check initial mapping in app-started telemetry
80+
def startedTelemetry = telemetryFlatMessages.find { it.request_type == "app-started" }
81+
assert startedTelemetry != null : "No app-started telemetry message found. Received: ${telemetryFlatMessages.collect { it.request_type }}"
82+
def startedConfigs = startedTelemetry.payload.configuration
83+
def initialMapping = startedConfigs.find {
84+
it.name == "service_mapping" && it.origin == "remote_config"
85+
}
86+
initialMapping != null
87+
initialMapping.value == "${ServiceMappingApplication.ORIGINAL_SERVICE_NAME}:${ServiceMappingApplication.MAPPED_SERVICE_NAME}"
88+
89+
// Check updated mapping in app-client-configuration-change telemetry
90+
def changeTelemetry = telemetryFlatMessages.find { it.request_type == "app-client-configuration-change" }
91+
assert changeTelemetry != null : "No app-client-configuration-change telemetry message found. Received: ${telemetryFlatMessages.collect { it.request_type }}"
92+
def changeConfigs = changeTelemetry.payload.configuration
93+
def updatedMapping = changeConfigs.find {
94+
it.name == "service_mapping" && it.origin == "remote_config"
95+
}
96+
updatedMapping != null
97+
updatedMapping.value == "${ServiceMappingApplication.ORIGINAL_SERVICE_NAME}:baz"
4498
}
4599
}

internal-api/src/main/java/datadog/trace/api/DynamicConfig.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package datadog.trace.api;
22

3+
import static datadog.trace.api.config.AppSecConfig.APPSEC_ENABLED;
34
import static datadog.trace.api.config.GeneralConfig.DATA_STREAMS_ENABLED;
45
import static datadog.trace.api.config.GeneralConfig.RUNTIME_METRICS_ENABLED;
56
import static datadog.trace.api.config.GeneralConfig.TRACE_DEBUG;
@@ -284,6 +285,10 @@ static void reportConfigChange(Snapshot newSnapshot) {
284285
update.put(RUNTIME_METRICS_ENABLED, newSnapshot.runtimeMetricsEnabled);
285286
update.put(LOGS_INJECTION_ENABLED, newSnapshot.logsInjectionEnabled);
286287
update.put(DATA_STREAMS_ENABLED, newSnapshot.dataStreamsEnabled);
288+
if (ConfigCollector.get().collect().get(APPSEC_ENABLED) != null
289+
&& ConfigCollector.get().collect().get(APPSEC_ENABLED).origin == ConfigOrigin.REMOTE) {
290+
update.put(APPSEC_ENABLED, ConfigCollector.get().collect().get(APPSEC_ENABLED).value);
291+
}
287292

288293
update.put(SERVICE_MAPPING, newSnapshot.serviceMapping);
289294
update.put(REQUEST_HEADER_TAGS, newSnapshot.requestHeaderTags);

0 commit comments

Comments
 (0)