From 27a056bcd4c2852ac8b8d45b8874299700f452b1 Mon Sep 17 00:00:00 2001 From: Valentin Zakharov Date: Fri, 28 Jun 2024 23:41:01 +0200 Subject: [PATCH] Report RASP span metrics --- .../appsec/gateway/AppSecRequestContext.java | 12 ++++++++++ .../datadog/appsec/gateway/GatewayBridge.java | 1 + .../powerwaf/PowerWAFStatsReporter.java | 22 +++++++++++++++---- .../PowerWAFStatsReporterSpecification.groovy | 22 ++++++++++++++++++- 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/AppSecRequestContext.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/AppSecRequestContext.java index 7a82a1eb8d2..44041e05ef4 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/AppSecRequestContext.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/AppSecRequestContext.java @@ -17,6 +17,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -115,6 +116,8 @@ public class AppSecRequestContext implements DataBundle, Closeable { private volatile boolean blocked; private volatile int timeouts; + private final AtomicInteger raspCounter = new AtomicInteger(); + private static final AtomicIntegerFieldUpdater TIMEOUTS_UPDATER = AtomicIntegerFieldUpdater.newUpdater(AppSecRequestContext.class, "timeouts"); @@ -398,6 +401,15 @@ public void setRespDataPublished(boolean respDataPublished) { this.respDataPublished = respDataPublished; } + public int getRaspCounter() { + return raspCounter.get(); + } + + public void increaseRaspCounter() { + raspCounter.incrementAndGet(); + } + + @Override public void close() { synchronized (this) { 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 4063d258144..65166d99cf7 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 @@ -480,6 +480,7 @@ public void init() { .add(KnownAddresses.DB_SQL_QUERY, sql) .build(); try { + ctx.increaseRaspCounter(); return producerService.publishDataEvent(subInfo, ctx, bundle, false); } catch (ExpiredSubscriberInfoException e) { dbSqlQuerySubInfo = null; diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/powerwaf/PowerWAFStatsReporter.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/powerwaf/PowerWAFStatsReporter.java index f730608e88a..a993f58f466 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/powerwaf/PowerWAFStatsReporter.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/powerwaf/PowerWAFStatsReporter.java @@ -8,8 +8,13 @@ import java.util.Collection; public class PowerWAFStatsReporter implements TraceSegmentPostProcessor { - private static final String TOTAL_DURATION_US_TAG = "_dd.appsec.waf.duration_ext"; - private static final String TOTAL_DDWAF_RUN_DURATION_US_TAG = "_dd.appsec.waf.duration"; + private static final String WAF_TOTAL_DURATION_US_TAG = "_dd.appsec.waf.duration_ext"; + private static final String WAF_TOTAL_DDWAF_RUN_DURATION_US_TAG = "_dd.appsec.waf.duration"; + + private static final String RASP_TOTAL_DURATION_US_TAG = "appsec.rasp.duration_ext"; + private static final String RASP_TOTAL_DDWAF_RUN_DURATION_US_TAG = "appsec.rasp.duration"; + + private static final String RASP_RULE_EVAL = "appsec.rasp.rule.eval"; private static final String RULE_FILE_VERSION = "_dd.appsec.event_rules.version"; public static final String TIMEOUTS_TAG = "_dd.appsec.waf.timeouts"; @@ -22,8 +27,17 @@ public void processTraceSegment( TraceSegment segment, AppSecRequestContext ctx, Collection collectedEvents) { PowerwafMetrics metrics = ctx.getWafMetrics(); if (metrics != null) { - segment.setTagTop(TOTAL_DURATION_US_TAG, metrics.getTotalRunTimeNs() / 1000L); - segment.setTagTop(TOTAL_DDWAF_RUN_DURATION_US_TAG, metrics.getTotalDdwafRunTimeNs() / 1000L); + long totalDurationMs = metrics.getTotalRunTimeNs() / 1000L; + long totalDdwafRunDurationMs = metrics.getTotalDdwafRunTimeNs() / 1000L; + + if (ctx.getRaspCounter() > 0) { + segment.setTagTop(RASP_TOTAL_DURATION_US_TAG, totalDurationMs); + segment.setTagTop(RASP_TOTAL_DDWAF_RUN_DURATION_US_TAG, totalDdwafRunDurationMs); + segment.setTagTop(RASP_RULE_EVAL, ctx.getRaspCounter()); + } else { + segment.setTagTop(WAF_TOTAL_DURATION_US_TAG, totalDurationMs); + segment.setTagTop(WAF_TOTAL_DDWAF_RUN_DURATION_US_TAG, totalDdwafRunDurationMs); + } String rulesVersion = this.rulesVersion; if (rulesVersion != null) { diff --git a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/powerwaf/PowerWAFStatsReporterSpecification.groovy b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/powerwaf/PowerWAFStatsReporterSpecification.groovy index 4d3d4c1eba6..1800e51d9a9 100644 --- a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/powerwaf/PowerWAFStatsReporterSpecification.groovy +++ b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/powerwaf/PowerWAFStatsReporterSpecification.groovy @@ -9,7 +9,7 @@ class PowerWAFStatsReporterSpecification extends DDSpecification { PowerWAFStatsReporter reporter = new PowerWAFStatsReporter() AppSecRequestContext ctx = Mock() - void 'reporter reports timings and version'() { + void 'reporter reports waf timings and version'() { setup: PowerwafMetrics metrics = new PowerwafMetrics() metrics.totalRunTimeNs = 2_000 @@ -38,4 +38,24 @@ class PowerWAFStatsReporterSpecification extends DDSpecification { 1 * ctx.getWafMetrics() >> null 0 * segment._(*_) } + + void 'reporter reports rasp metrics'() { + setup: + PowerwafMetrics metrics = new PowerwafMetrics() + metrics.totalRunTimeNs = 2_000 + metrics.totalDdwafRunTimeNs = 1_000 + TraceSegment segment = Mock() + reporter.rulesVersion = '1.2.3' + ctx.getRaspCounter() >> 4 + + when: + reporter.processTraceSegment(segment, ctx, []) + + then: + 1 * ctx.getWafMetrics() >> metrics + 1 * segment.setTagTop('appsec.rasp.duration', 1) + 1 * segment.setTagTop('appsec.rasp.duration_ext', 2) + 1 * segment.setTagTop('appsec.rasp.rule.eval', 4) + 1 * segment.setTagTop('_dd.appsec.event_rules.version', '1.2.3') + } }