Skip to content

Commit 2b6dc51

Browse files
committed
test(debugger): span probe budgets (#DEBUG-3797)
1 parent 7022c7a commit 2b6dc51

3 files changed

Lines changed: 96 additions & 0 deletions

File tree

manifests/java.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2695,6 +2695,7 @@ manifest:
26952695
spring-boot-undertow: v1.38.0
26962696
spring-boot-wildfly: v1.38.0
26972697
uds-spring-boot: v1.38.0
2698+
tests/debugger/test_debugger_probe_budgets.py::Test_Debugger_Probe_Budgets::test_span_probe_expression_budgets: bug (DEBUG-3797)
26982699
tests/debugger/test_debugger_probe_snapshot.py::Test_Debugger_Line_Probe_Snaphots:
26992700
- weblog_declaration:
27002701
"*": missing_feature

tests/debugger/test_debugger_probe_budgets.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,52 @@ def test_log_line_budgets(self):
9090
assert 1 <= snapshots_with_captures <= 20, (
9191
f"Expected 1-20 snapshot with captures, got {snapshots_with_captures} in {self.total_request_time} seconds"
9292
)
93+
94+
def setup_span_probe_expression_budgets(self):
95+
self.initialize_weblog_remote_config()
96+
97+
probes = debugger.read_probes("probe_span_method_budgets_expression")
98+
for probe in probes:
99+
probe["id"] = debugger.generate_probe_id("decor")
100+
101+
self.set_probes(probes)
102+
self.send_rc_probes()
103+
self.wait_for_all_probes(statuses=["INSTALLED"])
104+
105+
start_time = time.time()
106+
self.send_weblog_request("/debugger/budgets/1")
107+
for _ in range(149):
108+
self.send_weblog_request("/debugger/budgets/1", reset=False)
109+
end_time = time.time()
110+
self.total_request_time = end_time - start_time
111+
112+
# Allow time for the agent to receive data after the last request
113+
time.sleep(2)
114+
115+
def test_span_probe_expression_budgets(self):
116+
self.collect()
117+
self.assert_setup_ok()
118+
self.assert_rc_state_not_error()
119+
self.assert_all_weblog_responses_ok()
120+
121+
# Count all snapshot entries emitted for the span probe.
122+
# When a span probe's expression fails (e.g., "Cannot dereference field"),
123+
# error logs should be rate-limited to at most 1 per second.
124+
total_error_entries = 0
125+
for _id in self.probe_ids:
126+
if _id in self.probe_snapshots:
127+
total_error_entries += len(self.probe_snapshots[_id])
128+
129+
# Verify at least one error entry was generated (probe actually fired and failed)
130+
assert total_error_entries >= 1, (
131+
"Expected at least 1 error entry to verify the span probe expression error was logged, got 0"
132+
)
133+
134+
# Error entries should be rate-limited to at most 1 per second.
135+
# Allow a buffer for timing imprecision.
136+
max_expected = int(self.total_request_time) + 5
137+
assert total_error_entries <= max_expected, (
138+
f"Expected at most {max_expected} error entries (1/sec budget for "
139+
f"{self.total_request_time:.1f}s), got {total_error_entries}. "
140+
f"Span probe expression error logging should be rate-limited."
141+
)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
[
2+
{
3+
"language": "",
4+
"type": "",
5+
"id": "",
6+
"version": 0,
7+
"targetSpan": "ACTIVE",
8+
"decorations": [
9+
{
10+
"when": {
11+
"dsl": "",
12+
"json": {
13+
"gt": [
14+
{"ref": "loops"},
15+
0
16+
]
17+
}
18+
},
19+
"tags": [
20+
{
21+
"name": "BudgetsTag",
22+
"value": {
23+
"template": null,
24+
"segments": [
25+
{
26+
"dsl": "",
27+
"json": {
28+
"getmember": [
29+
{"ref": "clientTracer"},
30+
"nonExistentField"
31+
]
32+
}
33+
}
34+
]
35+
}
36+
}
37+
]
38+
}
39+
],
40+
"where": {
41+
"typeName": "ACTUAL_TYPE_NAME",
42+
"methodName": "Budgets",
43+
"sourceFile": null
44+
}
45+
}
46+
]

0 commit comments

Comments
 (0)