[AppSec] Emit rasp.error and rasp.rule.skipped telemetry - #9090
Conversation
Add the two missing RASP telemetry count metrics: rasp.error when the WAF returns an error for a RASP evaluation, and rasp.rule.skipped when the evaluation never reaches the WAF because of the request lifecycle. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Execution-Time Benchmarks Report ⏱️Execution-time results for samples comparing This PR (9090) and master. ✅ No regressions detected |
BenchmarksBenchmark execution time: 2026-08-20 18:10:41 Comparing candidate commit d07c891 in PR branch Found 1 performance improvements and 0 performance regressions! Performance is the same for 71 metrics, 0 unstable metrics, 65 known flaky benchmarks, 61 flaky benchmarks without significant changes.
|
| internal sealed partial class MetricsTelemetryCollector | ||
| { | ||
| private const int CountLength = 770; | ||
| private const int CountLength = 800; |
There was a problem hiding this comment.
Urgh, this number is getting quite large, I wonder if we're going to have to do something about it at some point 🙁
There was a problem hiding this comment.
Yup, I thought the same when I saw it
Summary of changes
Add the two missing RASP telemetry count metrics:
appsec.rasp.error— the WAF returned an error for a RASP evaluation, tagged bywaf_errorandrule_type/rule_variant.appsec.rasp.rule.skipped— a RASP evaluation never reached the WAF, tagged byreasonandrule_type/rule_variant.Reason for change
.NET was the only tracer not emitting these, so RASP errors and lifecycle-skipped evaluations were invisible in telemetry. Fixes APPSEC-69544.
Implementation details
Both metrics are recorded from
RaspModule, which is the only place that knows the address (and therefore the rule type) — no rule type has to be plumbed throughSecurityCoordinator/Context.CheckVulnerability,OnDownstreamRequestandOnDownstreamResponsehad a combinedrootSpan is null || rootSpan.IsFinished || rootSpan.Type != SpanTypes.Webguard. It is split so a finished span reportsafter-requestand the rest reportout-of-request. A missing security coordinator also reportsout-of-request.RunWaf. Anullresult means the WAF never produced one, reported aswaf_error:-127(binding error); otherwise the return code is mapped through the existingToWafErrorTag(). A timeout returns early, since it is already reported byrasp.timeout— same precedence asSecurityReporter.RecordWafTelemetry.RunWafalso returnsnullwhen the additive context was disposed between the lifecycle check and the call, i.e. the request ended in between. The newAppSecRequestContext.IsAdditiveContextDisposeddistinguishes that case so it is reported asrasp.rule.skipped{after-request}rather than a phantom binding error.OnDownstreamRequest/OnDownstreamResponsenow checkAddressEnabled(DownstreamUrl)up front, so a ruleset without SSRF rules doesn't report skips for instrumentation that isn't active.Tag shapes follow the intake spec in dd-go rather than another tracer's implementation. Note
rasp.rule.skippedcarries neitherwaf_versionnorevent_rules_version— the evaluation is skipped before the WAF is reached.The embedded
common_metrics.jsoncopy used byMetricTestsis updated; dd-go needs the same two entries after this merges.Test coverage
New
RaspModuleTelemetryTests(32 tests): both reasons across all 5 rule types, all WAF error codes, success codes and timeouts recording nothing, unknown addresses no-op, the absence ofwaf_versiontags, and the disposed-context vs binding-error split.MetricTestsvalidates both metrics against the intake spec.Other details
rasp.duration/rasp.duration_ext(distributions) are not included and will follow separately.🤖 Generated with Claude Code