Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions manifests/java.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2695,6 +2695,7 @@ manifest:
spring-boot-undertow: v1.38.0
spring-boot-wildfly: v1.38.0
uds-spring-boot: v1.38.0
tests/debugger/test_debugger_probe_budgets.py::Test_Debugger_Probe_Budgets::test_span_probe_expression_budgets: bug (DEBUG-3797)
tests/debugger/test_debugger_probe_snapshot.py::Test_Debugger_Line_Probe_Snaphots:
- weblog_declaration:
"*": missing_feature
Expand Down
49 changes: 49 additions & 0 deletions tests/debugger/test_debugger_probe_budgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,52 @@ def test_log_line_budgets(self):
assert 1 <= snapshots_with_captures <= 20, (
f"Expected 1-20 snapshot with captures, got {snapshots_with_captures} in {self.total_request_time} seconds"
)

def setup_span_probe_expression_budgets(self):
self.initialize_weblog_remote_config()

probes = debugger.read_probes("probe_span_method_budgets_expression")
for probe in probes:
probe["id"] = debugger.generate_probe_id("decor")

self.set_probes(probes)
self.send_rc_probes()
self.wait_for_all_probes(statuses=["INSTALLED"])

start_time = time.time()
self.send_weblog_request("/debugger/budgets/1")
for _ in range(149):
self.send_weblog_request("/debugger/budgets/1", reset=False)
end_time = time.time()
self.total_request_time = end_time - start_time

# Allow time for the agent to receive data after the last request
time.sleep(2)

def test_span_probe_expression_budgets(self):
self.collect()
self.assert_setup_ok()
self.assert_rc_state_not_error()
self.assert_all_weblog_responses_ok()

# Count all snapshot entries emitted for the span probe.
# When a span probe's expression fails (e.g., "Cannot dereference field"),
# error logs should be rate-limited to at most 1 per second.
total_error_entries = 0
for _id in self.probe_ids:
if _id in self.probe_snapshots:
total_error_entries += len(self.probe_snapshots[_id])

# Verify at least one error entry was generated (probe actually fired and failed)
assert total_error_entries >= 1, (
f"Expected at least 1 error entry to verify the span probe expression error was logged, got 0"
)

# Error entries should be rate-limited to at most 1 per second.
# Allow a buffer for timing imprecision.
max_expected = int(self.total_request_time) + 5
assert total_error_entries <= max_expected, (
f"Expected at most {max_expected} error entries (1/sec budget for "
f"{self.total_request_time:.1f}s), got {total_error_entries}. "
f"Span probe expression error logging should be rate-limited."
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
[
{
"language": "",
"type": "",
"id": "",
"version": 0,
"targetSpan": "ACTIVE",
"decorations": [
{
"when": {
"dsl": "",
"json": {
"gt": [
{"ref": "loops"},
0
]
}
},
"tags": [
{
"name": "BudgetsTag",
"value": {
"template": null,
"segments": [
{
"dsl": "",
"json": {
"getmember": [
{"ref": "clientTracer"},
"nonExistentField"
]
}
}
]
}
}
]
}
],
"where": {
"typeName": "ACTUAL_TYPE_NAME",
"methodName": "Budgets",
"sourceFile": null
}
}
]