Skip to content

Commit 2ad2645

Browse files
committed
Add tag rate_limited
1 parent 41779c2 commit 2ad2645

File tree

4 files changed

+75
-37
lines changed

4 files changed

+75
-37
lines changed

dd-java-agent/appsec/src/main/java/com/datadog/appsec/powerwaf/PowerWAFModule.java

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -494,23 +494,28 @@ public void onDataAvailable(
494494
}
495495
Collection<AppSecEvent> events = buildEvents(resultWithData);
496496

497-
if (!events.isEmpty() && !reqCtx.isThrottled(rateLimiter)) {
498-
AgentSpan activeSpan = AgentTracer.get().activeSpan();
499-
if (activeSpan != null) {
500-
log.debug("Setting force-keep tag on the current span");
501-
// Keep event related span, because it could be ignored in case of
502-
// reduced datadog sampling rate.
503-
activeSpan.getLocalRootSpan().setTag(Tags.ASM_KEEP, true);
504-
// If APM is disabled, inform downstream services that the current
505-
// distributed trace contains at least one ASM event and must inherit
506-
// the given force-keep priority
507-
activeSpan.getLocalRootSpan().setTag(Tags.PROPAGATED_APPSEC, true);
497+
if (!events.isEmpty()) {
498+
if (!reqCtx.isThrottled(rateLimiter)) {
499+
AgentSpan activeSpan = AgentTracer.get().activeSpan();
500+
if (activeSpan != null) {
501+
log.debug("Setting force-keep tag on the current span");
502+
// Keep event related span, because it could be ignored in case of
503+
// reduced datadog sampling rate.
504+
activeSpan.getLocalRootSpan().setTag(Tags.ASM_KEEP, true);
505+
// If APM is disabled, inform downstream services that the current
506+
// distributed trace contains at least one ASM event and must inherit
507+
// the given force-keep priority
508+
activeSpan.getLocalRootSpan().setTag(Tags.PROPAGATED_APPSEC, true);
509+
} else {
510+
// If active span is not available the ASK_KEEP tag will be set in the GatewayBridge
511+
// when the request ends
512+
log.debug("There is no active span available");
513+
}
514+
reqCtx.reportEvents(events);
508515
} else {
509-
// If active span is not available the ASK_KEEP tag will be set in the GatewayBridge
510-
// when the request ends
511-
log.debug("There is no active span available");
516+
log.debug("Rate limited WAF events");
517+
WafMetricCollector.get().wafRequestRateLimited();
512518
}
513-
reqCtx.reportEvents(events);
514519
}
515520

516521
if (flow.isBlocking()) {

internal-api/src/main/java/datadog/trace/api/telemetry/WafMetricCollector.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ private WafMetricCollector() {
3535
private static final AtomicRequestCounter wafBlockedRequestCounter = new AtomicRequestCounter();
3636
private static final AtomicRequestCounter wafTimeoutRequestCounter = new AtomicRequestCounter();
3737
private static final AtomicRequestCounter wafErrorRequestCounter = new AtomicRequestCounter();
38+
private static final AtomicRequestCounter wafRateLimitedRequestCounter =
39+
new AtomicRequestCounter();
3840
private static final AtomicLongArray raspRuleEvalCounter =
3941
new AtomicLongArray(RuleType.getNumValues());
4042
private static final AtomicLongArray raspRuleMatchCounter =
@@ -97,6 +99,10 @@ public void wafRequestError() {
9799
wafErrorRequestCounter.increment();
98100
}
99101

102+
public void wafRequestRateLimited() {
103+
wafRateLimitedRequestCounter.increment();
104+
}
105+
100106
public void raspRuleEval(final RuleType ruleType) {
101107
raspRuleEvalCounter.incrementAndGet(ruleType.ordinal());
102108
}
@@ -132,6 +138,8 @@ public Collection<WafMetric> drain() {
132138

133139
@Override
134140
public void prepareMetrics() {
141+
final boolean isRateLimited = wafRateLimitedRequestCounter.getAndReset() > 0;
142+
135143
// Requests
136144
if (wafRequestCounter.get() > 0) {
137145
if (!rawMetricsQueue.offer(
@@ -142,7 +150,8 @@ public void prepareMetrics() {
142150
false,
143151
false,
144152
false,
145-
false))) {
153+
false,
154+
isRateLimited))) {
146155
return;
147156
}
148157
}
@@ -157,7 +166,8 @@ public void prepareMetrics() {
157166
true,
158167
false,
159168
false,
160-
false))) {
169+
false,
170+
isRateLimited))) {
161171
return;
162172
}
163173
}
@@ -172,7 +182,8 @@ public void prepareMetrics() {
172182
true,
173183
true,
174184
false,
175-
false))) {
185+
false,
186+
isRateLimited))) {
176187
return;
177188
}
178189
}
@@ -187,7 +198,8 @@ public void prepareMetrics() {
187198
false,
188199
false,
189200
false,
190-
true))) {
201+
true,
202+
isRateLimited))) {
191203
return;
192204
}
193205
}
@@ -202,7 +214,8 @@ public void prepareMetrics() {
202214
false,
203215
false,
204216
true,
205-
false))) {
217+
false,
218+
isRateLimited))) {
206219
return;
207220
}
208221
}
@@ -332,7 +345,8 @@ public WafRequestsRawMetric(
332345
final boolean triggered,
333346
final boolean blocked,
334347
final boolean wafError,
335-
final boolean wafTimeout) {
348+
final boolean wafTimeout,
349+
final boolean rateLimited) {
336350
super(
337351
"waf.requests",
338352
counter,
@@ -341,7 +355,8 @@ public WafRequestsRawMetric(
341355
"rule_triggered:" + triggered,
342356
"request_blocked:" + blocked,
343357
"waf_error:" + wafError,
344-
"waf_timeout:" + wafTimeout);
358+
"waf_timeout:" + wafTimeout,
359+
"rate_limited:" + rateLimited);
345360
}
346361
}
347362

internal-api/src/test/groovy/datadog/trace/api/telemetry/WafMetricCollectorTest.groovy

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class WafMetricCollectorTest extends DDSpecification {
2828
WafMetricCollector.get().wafRequestBlocked()
2929
WafMetricCollector.get().wafRequestTimeout()
3030
WafMetricCollector.get().wafRequestError()
31+
WafMetricCollector.get().wafRequestRateLimited()
3132
WafMetricCollector.get().raspRuleEval(RuleType.SQL_INJECTION)
3233
WafMetricCollector.get().raspRuleEval(RuleType.SQL_INJECTION)
3334
WafMetricCollector.get().raspRuleMatch(RuleType.SQL_INJECTION)
@@ -71,7 +72,8 @@ class WafMetricCollectorTest extends DDSpecification {
7172
'rule_triggered:false',
7273
'request_blocked:false',
7374
'waf_error:false',
74-
'waf_timeout:false'
75+
'waf_timeout:false',
76+
'rate_limited:true'
7577
].toSet()
7678

7779
def requestTriggeredMetric = (WafMetricCollector.WafRequestsRawMetric)metrics[4]
@@ -84,7 +86,8 @@ class WafMetricCollectorTest extends DDSpecification {
8486
'rule_triggered:true',
8587
'request_blocked:false',
8688
'waf_error:false',
87-
'waf_timeout:false'
89+
'waf_timeout:false',
90+
'rate_limited:true'
8891
].toSet()
8992

9093

@@ -99,7 +102,8 @@ class WafMetricCollectorTest extends DDSpecification {
99102
'rule_triggered:true',
100103
'request_blocked:true',
101104
'waf_error:false',
102-
'waf_timeout:false'
105+
'waf_timeout:false',
106+
'rate_limited:true'
103107
].toSet()
104108

105109
def requestTimeoutMetric = (WafMetricCollector.WafRequestsRawMetric)metrics[6]
@@ -113,7 +117,8 @@ class WafMetricCollectorTest extends DDSpecification {
113117
'rule_triggered:false',
114118
'request_blocked:false',
115119
'waf_error:false',
116-
'waf_timeout:true'
120+
'waf_timeout:true',
121+
'rate_limited:true'
117122
].toSet()
118123

119124
def requestWafErrorMetric = (WafMetricCollector.WafRequestsRawMetric)metrics[7]
@@ -127,7 +132,8 @@ class WafMetricCollectorTest extends DDSpecification {
127132
'rule_triggered:false',
128133
'request_blocked:false',
129134
'waf_error:true',
130-
'waf_timeout:false'
135+
'waf_timeout:false',
136+
'rate_limited:true'
131137
].toSet()
132138

133139
def raspRuleEvalSqli = (WafMetricCollector.RaspRuleEval)metrics[8]

telemetry/src/test/groovy/datadog/telemetry/metric/WafMetricPeriodicActionSpecification.groovy

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification {
5050
WafMetricCollector.get().wafRequest()
5151
WafMetricCollector.get().wafRequestTimeout()
5252
WafMetricCollector.get().wafRequestError()
53+
WafMetricCollector.get().wafRequestRateLimited()
5354
WafMetricCollector.get().prepareMetrics()
5455
periodicAction.doIteration(telemetryService)
5556

@@ -68,7 +69,8 @@ class WafMetricPeriodicActionSpecification extends DDSpecification {
6869
'rule_triggered:false',
6970
'request_blocked:false',
7071
'waf_error:false',
71-
'waf_timeout:false'
72+
'waf_timeout:false',
73+
'rate_limited:true'
7274
]
7375
} )
7476
1 * telemetryService.addMetric( { Metric metric ->
@@ -81,7 +83,8 @@ class WafMetricPeriodicActionSpecification extends DDSpecification {
8183
'rule_triggered:true',
8284
'request_blocked:false',
8385
'waf_error:false',
84-
'waf_timeout:false'
86+
'waf_timeout:false',
87+
'rate_limited:true'
8588
]
8689
} )
8790
1 * telemetryService.addMetric( { Metric metric ->
@@ -94,7 +97,8 @@ class WafMetricPeriodicActionSpecification extends DDSpecification {
9497
'rule_triggered:true',
9598
'request_blocked:true',
9699
'waf_error:false',
97-
'waf_timeout:false'
100+
'waf_timeout:false',
101+
'rate_limited:true'
98102
]
99103
} )
100104
1 * telemetryService.addMetric( { Metric metric ->
@@ -107,7 +111,8 @@ class WafMetricPeriodicActionSpecification extends DDSpecification {
107111
'rule_triggered:false',
108112
'request_blocked:false',
109113
'waf_error:false',
110-
'waf_timeout:true'
114+
'waf_timeout:true',
115+
'rate_limited:true'
111116
]
112117
} )
113118
1 * telemetryService.addMetric( { Metric metric ->
@@ -120,7 +125,8 @@ class WafMetricPeriodicActionSpecification extends DDSpecification {
120125
'rule_triggered:false',
121126
'request_blocked:false',
122127
'waf_error:true',
123-
'waf_timeout:false'
128+
'waf_timeout:false',
129+
'rate_limited:true'
124130
]
125131
} )
126132
0 * _._
@@ -132,6 +138,7 @@ class WafMetricPeriodicActionSpecification extends DDSpecification {
132138
WafMetricCollector.get().wafRequestBlocked()
133139
WafMetricCollector.get().wafRequestTimeout()
134140
WafMetricCollector.get().wafRequestError()
141+
WafMetricCollector.get().wafRequestRateLimited()
135142
WafMetricCollector.get().prepareMetrics()
136143
periodicAction.doIteration(telemetryService)
137144

@@ -150,7 +157,8 @@ class WafMetricPeriodicActionSpecification extends DDSpecification {
150157
'rule_triggered:false',
151158
'request_blocked:false',
152159
'waf_error:false',
153-
'waf_timeout:false'
160+
'waf_timeout:false',
161+
'rate_limited:true'
154162
]
155163
} )
156164
1 * telemetryService.addMetric( { Metric metric ->
@@ -163,7 +171,8 @@ class WafMetricPeriodicActionSpecification extends DDSpecification {
163171
'rule_triggered:true',
164172
'request_blocked:false',
165173
'waf_error:false',
166-
'waf_timeout:false'
174+
'waf_timeout:false',
175+
'rate_limited:true'
167176
]
168177
} )
169178
1 * telemetryService.addMetric( { Metric metric ->
@@ -176,7 +185,8 @@ class WafMetricPeriodicActionSpecification extends DDSpecification {
176185
'rule_triggered:true',
177186
'request_blocked:true',
178187
'waf_error:false',
179-
'waf_timeout:false'
188+
'waf_timeout:false',
189+
'rate_limited:true'
180190
]
181191
} )
182192
1 * telemetryService.addMetric( { Metric metric ->
@@ -189,7 +199,8 @@ class WafMetricPeriodicActionSpecification extends DDSpecification {
189199
'rule_triggered:false',
190200
'request_blocked:false',
191201
'waf_error:false',
192-
'waf_timeout:true'
202+
'waf_timeout:true',
203+
'rate_limited:true'
193204
]
194205
} )
195206
1 * telemetryService.addMetric( { Metric metric ->
@@ -202,7 +213,8 @@ class WafMetricPeriodicActionSpecification extends DDSpecification {
202213
'rule_triggered:false',
203214
'request_blocked:false',
204215
'waf_error:true',
205-
'waf_timeout:false'
216+
'waf_timeout:false',
217+
'rate_limited:true'
206218
]
207219
} )
208220
0 * _._

0 commit comments

Comments
 (0)