From d41d61b6ff489bda96fae8a427e7c77fd803a47a Mon Sep 17 00:00:00 2001 From: "timothy.seemann" Date: Tue, 27 Oct 2026 12:56:56 -0400 Subject: [PATCH 1/9] [debugger] Add repro tests for map index values and silent metric value errors --- .../test_debugger_capture_expressions.py | 18 ++++++ .../test_debugger_metric_value_errors.py | 57 +++++++++++++++++++ .../probes/probe_metric_value_error.json | 21 +++++++ 3 files changed, 96 insertions(+) create mode 100644 tests/debugger/test_debugger_metric_value_errors.py create mode 100644 tests/debugger/utils/probes/probe_metric_value_error.json diff --git a/tests/debugger/test_debugger_capture_expressions.py b/tests/debugger/test_debugger_capture_expressions.py index 0898a53aaa2..51bcc93ffb3 100644 --- a/tests/debugger/test_debugger_capture_expressions.py +++ b/tests/debugger/test_debugger_capture_expressions.py @@ -202,6 +202,24 @@ def test_complex_capture_expressions(self): self._validate_capture_expressions(expected_captures) + def setup_complex_capture_expressions_dictionary_value(self): + self._setup("probe_capture_expressions_complex", "/debugger/expression?inputValue=testValue", "log", lines=None) + + def test_complex_capture_expressions_dictionary_value(self): + """``testStruct.Dictionary['two']`` names an existing key, so it must capture 2, not a not-captured marker.""" + self._assert() + + expected_captures = { + probe_id: { + "dictionary_value": lambda v: ( + isinstance(v, dict) and "notCapturedReason" not in v and str(v.get("value")) == "2" + ), + } + for probe_id in self.probe_ids + } + + self._validate_capture_expressions(expected_captures) + @features.debugger_line_probe @scenarios.debugger_probes_snapshot diff --git a/tests/debugger/test_debugger_metric_value_errors.py b/tests/debugger/test_debugger_metric_value_errors.py new file mode 100644 index 00000000000..2083c015f8f --- /dev/null +++ b/tests/debugger/test_debugger_metric_value_errors.py @@ -0,0 +1,57 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the the Apache License Version 2.0. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2021 Datadog, Inc. + +"""Compliance tests: a metric probe whose value expression fails must not fail silently.""" + +import tests.debugger.utils as debugger +from utils import features, scenarios + + +@features.debugger_expression_language +@scenarios.debugger_probes_snapshot +class Test_Debugger_Metric_Value_Error(debugger.BaseDebuggerTest): + """Compliance: a broken metric value expression must surface as an ERROR status or an evaluation error.""" + + def setup_metric_value_error_is_reported(self) -> None: + self.initialize_weblog_remote_config() + + probes = debugger.read_probes("probe_metric_value_error") + for probe in probes: + probe["id"] = debugger.generate_probe_id("metric") + + self.set_probes(probes) + self.send_rc_probes() + self.wait_for_all_probes(statuses=["INSTALLED", "ERROR"], timeout=30) + self.send_weblog_request("/debugger/metric/1") + self.wait_for_all_snapshots(timeout=10) + + def test_metric_value_error_is_reported(self) -> None: + """The value references the unbound variable ``definitelyDoesNotExist``, so no metric point can ever be produced. + + A conforming tracer either rejects the probe (status=ERROR) or keeps it installed and emits a probe + result whose ``evaluationErrors[]`` names the failing variable. + """ + self.collect() + self.assert_setup_ok() + + for probe_id in self.probe_ids: + diag = self.probe_diagnostics.get(probe_id) + assert diag is not None, "The probe did not receive any diagnostic." + if diag["status"] == "ERROR": + continue + + evaluation_errors = [] + for envelope in self.probe_snapshots.get(probe_id, []): + snap = envelope.get("debugger", {}).get("snapshot") or envelope.get("debugger.snapshot") or {} + evaluation_errors.extend(snap.get("evaluationErrors") or []) + + assert any( + "definitelyDoesNotExist" in str(entry.get("expr", "")) + or "definitelyDoesNotExist" in str(entry.get("message", "")) + for entry in evaluation_errors + ), ( + f"The probe reached status {diag['status']!r} and reported no evaluation error naming " + f"'definitelyDoesNotExist' (errors: {evaluation_errors!r}). The metric can never emit a point, " + f"so the failure must be visible to the user." + ) diff --git a/tests/debugger/utils/probes/probe_metric_value_error.json b/tests/debugger/utils/probes/probe_metric_value_error.json new file mode 100644 index 00000000000..2f8776d5927 --- /dev/null +++ b/tests/debugger/utils/probes/probe_metric_value_error.json @@ -0,0 +1,21 @@ +[ + { + "language": "", + "type": "", + "id": "", + "version": 0, + "kind": "GAUGE", + "metricName": "system_tests.debugger.metric_value_error", + "value": { + "dsl": "definitelyDoesNotExist", + "json": { + "ref": "definitelyDoesNotExist" + } + }, + "where": { + "typeName": "ACTUAL_TYPE_NAME", + "methodName": "MetricProbe", + "sourceFile": null + } + } +] From ccbde9ec5944e0770545a1827597c0d4d1c4bcf9 Mon Sep 17 00:00:00 2001 From: "timothy.seemann" Date: Tue, 27 Oct 2026 16:07:43 -0400 Subject: [PATCH 2/9] [debugger] Annotate evaluation_errors for mypy --- tests/debugger/test_debugger_metric_value_errors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/debugger/test_debugger_metric_value_errors.py b/tests/debugger/test_debugger_metric_value_errors.py index 2083c015f8f..649b0072397 100644 --- a/tests/debugger/test_debugger_metric_value_errors.py +++ b/tests/debugger/test_debugger_metric_value_errors.py @@ -41,7 +41,7 @@ def test_metric_value_error_is_reported(self) -> None: if diag["status"] == "ERROR": continue - evaluation_errors = [] + evaluation_errors: list[dict] = [] for envelope in self.probe_snapshots.get(probe_id, []): snap = envelope.get("debugger", {}).get("snapshot") or envelope.get("debugger.snapshot") or {} evaluation_errors.extend(snap.get("evaluationErrors") or []) From 32eb30c3952b836c5acfa4989c185fbc33e39e03 Mon Sep 17 00:00:00 2001 From: "timothy.seemann" Date: Tue, 27 Oct 2026 16:09:11 -0400 Subject: [PATCH 3/9] [debugger] Scope repro tests to Go: static template error and missing-key condition --- .../test_debugger_go_expression_errors.py | 76 +++++++++++++++++++ .../test_debugger_metric_value_errors.py | 57 -------------- .../probes/probe_metric_value_error.json | 21 ----- .../probe_missing_map_key_condition.json | 31 ++++++++ .../probes/probe_static_template_error.json | 26 +++++++ 5 files changed, 133 insertions(+), 78 deletions(-) create mode 100644 tests/debugger/test_debugger_go_expression_errors.py delete mode 100644 tests/debugger/test_debugger_metric_value_errors.py delete mode 100644 tests/debugger/utils/probes/probe_metric_value_error.json create mode 100644 tests/debugger/utils/probes/probe_missing_map_key_condition.json create mode 100644 tests/debugger/utils/probes/probe_static_template_error.json diff --git a/tests/debugger/test_debugger_go_expression_errors.py b/tests/debugger/test_debugger_go_expression_errors.py new file mode 100644 index 00000000000..c9c809873b7 --- /dev/null +++ b/tests/debugger/test_debugger_go_expression_errors.py @@ -0,0 +1,76 @@ +# Unless explicitly stated otherwise all files in this repository are licensed under the the Apache License Version 2.0. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2021 Datadog, Inc. + +"""Go expression errors that the system-probe can detect, because Go types are fixed at compile time.""" + +import tests.debugger.utils as debugger +from utils import context, features, irrelevant, scenarios + + +class _GoExpressionTestBase(debugger.BaseDebuggerTest): + def _setup_probes(self, probes_name: str, install_statuses: list[str]) -> None: + self.initialize_weblog_remote_config() + + probes = debugger.read_probes(probes_name) + for probe in probes: + probe["id"] = debugger.generate_probe_id("log") + + self.set_probes(probes) + self.send_rc_probes() + self.wait_for_all_probes(statuses=install_statuses, timeout=30) + self.send_weblog_request("/debugger/expression?inputValue=asd") + self.wait_for_all_snapshots(timeout=10) + + +@features.debugger_expression_language +@scenarios.debugger_probes_snapshot +@irrelevant(context.library != "golang", reason="Only Go checks expression types at install time") +class Test_Debugger_Go_Static_Template_Error(_GoExpressionTestBase): + """A template the system-probe already knows can never evaluate must be rejected, like the same condition is.""" + + def setup_static_template_error_probe_rejected(self) -> None: + self._setup_probes("probe_static_template_error", ["INSTALLED", "ERROR"]) + + def test_static_template_error_probe_rejected(self) -> None: + """``testStruct.Dictionary.two`` is a member access on a ``map[string]int``. + + The same expression in a ``when`` condition is rejected with ConditionExpressionUnresolvable. + In a log template it must also reach status=ERROR, not stay installed and print the error inline. + """ + self.collect() + self.assert_setup_ok() + + for probe_id in self.probe_ids: + diag = self.probe_diagnostics.get(probe_id) + assert diag is not None, "The probe did not receive any diagnostic." + assert diag["status"] == "ERROR", ( + f"Probe reached status {diag['status']!r}; a template with a member access on a map can never " + f"evaluate, so it must be rejected with status=ERROR like the equivalent condition." + ) + + +@features.debugger_expression_language +@scenarios.debugger_probes_snapshot +@irrelevant(context.library != "golang", reason="Go-specific repro for map index conditions") +class Test_Debugger_Go_Missing_Map_Key_Condition(_GoExpressionTestBase): + """A condition on a key that isn't in the map must not fire.""" + + def setup_missing_map_key_condition_does_not_fire(self) -> None: + self._setup_probes("probe_missing_map_key_condition", ["INSTALLED"]) + + def test_missing_map_key_condition_does_not_fire(self) -> None: + """``testStruct.Dictionary['nope'] == 1``: in Go a missing key reads as 0, so the condition is false. + + A conforming tracer emits nothing, or an error-only snapshot without captured data. + """ + self.collect() + self.assert_setup_ok() + + for probe_id in self.probe_ids: + for envelope in self.probe_snapshots.get(probe_id, []): + snap = envelope.get("debugger", {}).get("snapshot") or envelope.get("debugger.snapshot") or {} + assert not debugger.captures_contain_data(snap.get("captures")), ( + "The probe emitted a snapshot with captured data, so the condition fired as if true. " + "A missing key in a map[string]int reads as 0, and 0 == 1 is false." + ) diff --git a/tests/debugger/test_debugger_metric_value_errors.py b/tests/debugger/test_debugger_metric_value_errors.py deleted file mode 100644 index 649b0072397..00000000000 --- a/tests/debugger/test_debugger_metric_value_errors.py +++ /dev/null @@ -1,57 +0,0 @@ -# Unless explicitly stated otherwise all files in this repository are licensed under the the Apache License Version 2.0. -# This product includes software developed at Datadog (https://www.datadoghq.com/). -# Copyright 2021 Datadog, Inc. - -"""Compliance tests: a metric probe whose value expression fails must not fail silently.""" - -import tests.debugger.utils as debugger -from utils import features, scenarios - - -@features.debugger_expression_language -@scenarios.debugger_probes_snapshot -class Test_Debugger_Metric_Value_Error(debugger.BaseDebuggerTest): - """Compliance: a broken metric value expression must surface as an ERROR status or an evaluation error.""" - - def setup_metric_value_error_is_reported(self) -> None: - self.initialize_weblog_remote_config() - - probes = debugger.read_probes("probe_metric_value_error") - for probe in probes: - probe["id"] = debugger.generate_probe_id("metric") - - self.set_probes(probes) - self.send_rc_probes() - self.wait_for_all_probes(statuses=["INSTALLED", "ERROR"], timeout=30) - self.send_weblog_request("/debugger/metric/1") - self.wait_for_all_snapshots(timeout=10) - - def test_metric_value_error_is_reported(self) -> None: - """The value references the unbound variable ``definitelyDoesNotExist``, so no metric point can ever be produced. - - A conforming tracer either rejects the probe (status=ERROR) or keeps it installed and emits a probe - result whose ``evaluationErrors[]`` names the failing variable. - """ - self.collect() - self.assert_setup_ok() - - for probe_id in self.probe_ids: - diag = self.probe_diagnostics.get(probe_id) - assert diag is not None, "The probe did not receive any diagnostic." - if diag["status"] == "ERROR": - continue - - evaluation_errors: list[dict] = [] - for envelope in self.probe_snapshots.get(probe_id, []): - snap = envelope.get("debugger", {}).get("snapshot") or envelope.get("debugger.snapshot") or {} - evaluation_errors.extend(snap.get("evaluationErrors") or []) - - assert any( - "definitelyDoesNotExist" in str(entry.get("expr", "")) - or "definitelyDoesNotExist" in str(entry.get("message", "")) - for entry in evaluation_errors - ), ( - f"The probe reached status {diag['status']!r} and reported no evaluation error naming " - f"'definitelyDoesNotExist' (errors: {evaluation_errors!r}). The metric can never emit a point, " - f"so the failure must be visible to the user." - ) diff --git a/tests/debugger/utils/probes/probe_metric_value_error.json b/tests/debugger/utils/probes/probe_metric_value_error.json deleted file mode 100644 index 2f8776d5927..00000000000 --- a/tests/debugger/utils/probes/probe_metric_value_error.json +++ /dev/null @@ -1,21 +0,0 @@ -[ - { - "language": "", - "type": "", - "id": "", - "version": 0, - "kind": "GAUGE", - "metricName": "system_tests.debugger.metric_value_error", - "value": { - "dsl": "definitelyDoesNotExist", - "json": { - "ref": "definitelyDoesNotExist" - } - }, - "where": { - "typeName": "ACTUAL_TYPE_NAME", - "methodName": "MetricProbe", - "sourceFile": null - } - } -] diff --git a/tests/debugger/utils/probes/probe_missing_map_key_condition.json b/tests/debugger/utils/probes/probe_missing_map_key_condition.json new file mode 100644 index 00000000000..7a082dcdbba --- /dev/null +++ b/tests/debugger/utils/probes/probe_missing_map_key_condition.json @@ -0,0 +1,31 @@ +[ + { + "language": "", + "type": "", + "id": "", + "version": 0, + "where": { + "typeName": "ACTUAL_TYPE_NAME", + "methodName": "Expression", + "sourceFile": null + }, + "when": { + "dsl": "testStruct.Dictionary['nope'] == 1", + "json": { + "eq": [ + { + "index": [ + {"getmember": [{"ref": "testStruct"}, "Dictionary"]}, + "nope" + ] + }, + 1 + ] + } + }, + "captureSnapshot": true, + "segments": [ + {"str": "missing-map-key condition fired"} + ] + } +] diff --git a/tests/debugger/utils/probes/probe_static_template_error.json b/tests/debugger/utils/probes/probe_static_template_error.json new file mode 100644 index 00000000000..13b31d97dee --- /dev/null +++ b/tests/debugger/utils/probes/probe_static_template_error.json @@ -0,0 +1,26 @@ +[ + { + "language": "", + "type": "", + "id": "", + "version": 0, + "where": { + "typeName": "ACTUAL_TYPE_NAME", + "methodName": "Expression", + "sourceFile": null + }, + "captureSnapshot": false, + "segments": [ + {"str": "dot on map: "}, + { + "dsl": "testStruct.Dictionary.two", + "json": { + "getmember": [ + {"getmember": [{"ref": "testStruct"}, "Dictionary"]}, + "two" + ] + } + } + ] + } +] From 12232fc60798da49f2fdb0c54c72cfaecaed0b46 Mon Sep 17 00:00:00 2001 From: "timothy.seemann" Date: Tue, 27 Oct 2026 16:13:41 -0400 Subject: [PATCH 4/9] [debugger] Type install statuses as ProbeStatus --- tests/debugger/test_debugger_go_expression_errors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/debugger/test_debugger_go_expression_errors.py b/tests/debugger/test_debugger_go_expression_errors.py index c9c809873b7..e9a65d7a575 100644 --- a/tests/debugger/test_debugger_go_expression_errors.py +++ b/tests/debugger/test_debugger_go_expression_errors.py @@ -9,7 +9,7 @@ class _GoExpressionTestBase(debugger.BaseDebuggerTest): - def _setup_probes(self, probes_name: str, install_statuses: list[str]) -> None: + def _setup_probes(self, probes_name: str, install_statuses: list[debugger.ProbeStatus]) -> None: self.initialize_weblog_remote_config() probes = debugger.read_probes(probes_name) From 5655297a7e666bb4ec4ef3cbeda463ab577350ca Mon Sep 17 00:00:00 2001 From: "timothy.seemann" Date: Tue, 27 Oct 2026 16:31:36 -0400 Subject: [PATCH 5/9] [debugger] Cover unknown variable and missing field in Go static template test --- .../test_debugger_go_expression_errors.py | 11 ++-- .../probes/probe_static_template_error.json | 64 ++++++++++++++++++- 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/tests/debugger/test_debugger_go_expression_errors.py b/tests/debugger/test_debugger_go_expression_errors.py index e9a65d7a575..aeb4c1eef62 100644 --- a/tests/debugger/test_debugger_go_expression_errors.py +++ b/tests/debugger/test_debugger_go_expression_errors.py @@ -33,10 +33,11 @@ def setup_static_template_error_probe_rejected(self) -> None: self._setup_probes("probe_static_template_error", ["INSTALLED", "ERROR"]) def test_static_template_error_probe_rejected(self) -> None: - """``testStruct.Dictionary.two`` is a member access on a ``map[string]int``. + """Each template references something the system-probe resolves at install time and can't find. - The same expression in a ``when`` condition is rejected with ConditionExpressionUnresolvable. - In a log template it must also reach status=ERROR, not stay installed and print the error inline. + A member access on a ``map[string]int``, an unknown variable, and a missing struct field are all + rejected with an ERROR diagnostic when used in a ``when`` condition. In a log template they must also + reach status=ERROR, not stay installed and print the error inline. """ self.collect() self.assert_setup_ok() @@ -45,8 +46,8 @@ def test_static_template_error_probe_rejected(self) -> None: diag = self.probe_diagnostics.get(probe_id) assert diag is not None, "The probe did not receive any diagnostic." assert diag["status"] == "ERROR", ( - f"Probe reached status {diag['status']!r}; a template with a member access on a map can never " - f"evaluate, so it must be rejected with status=ERROR like the equivalent condition." + f"Probe reached status {diag['status']!r}; its template can never evaluate, so it must be " + f"rejected with status=ERROR like the equivalent condition." ) diff --git a/tests/debugger/utils/probes/probe_static_template_error.json b/tests/debugger/utils/probes/probe_static_template_error.json index 13b31d97dee..9f1a3076892 100644 --- a/tests/debugger/utils/probes/probe_static_template_error.json +++ b/tests/debugger/utils/probes/probe_static_template_error.json @@ -11,16 +11,76 @@ }, "captureSnapshot": false, "segments": [ - {"str": "dot on map: "}, + { + "str": "dot on map: " + }, { "dsl": "testStruct.Dictionary.two", "json": { "getmember": [ - {"getmember": [{"ref": "testStruct"}, "Dictionary"]}, + { + "getmember": [ + { + "ref": "testStruct" + }, + "Dictionary" + ] + }, "two" ] } } ] + }, + { + "language": "", + "type": "", + "id": "", + "version": 0, + "where": { + "typeName": "ACTUAL_TYPE_NAME", + "methodName": "Expression", + "sourceFile": null + }, + "captureSnapshot": false, + "segments": [ + { + "str": "unknown variable: " + }, + { + "dsl": "definitelyDoesNotExist", + "json": { + "ref": "definitelyDoesNotExist" + } + } + ] + }, + { + "language": "", + "type": "", + "id": "", + "version": 0, + "where": { + "typeName": "ACTUAL_TYPE_NAME", + "methodName": "Expression", + "sourceFile": null + }, + "captureSnapshot": false, + "segments": [ + { + "str": "missing struct field: " + }, + { + "dsl": "testStruct.DefinitelyDoesNotExist", + "json": { + "getmember": [ + { + "ref": "testStruct" + }, + "DefinitelyDoesNotExist" + ] + } + } + ] } ] From a121cd1c73fff62f89ab897b06bf41fa9697426f Mon Sep 17 00:00:00 2001 From: "timothy.seemann" Date: Tue, 27 Oct 2026 16:52:17 -0400 Subject: [PATCH 6/9] [debugger] Gate dictionary value test like complex capture test for Ruby and .NET --- manifests/dotnet.yml | 5 +++++ manifests/ruby.yml | 2 ++ 2 files changed, 7 insertions(+) diff --git a/manifests/dotnet.yml b/manifests/dotnet.yml index 6133abc9d72..dfc03f93b3a 100644 --- a/manifests/dotnet.yml +++ b/manifests/dotnet.yml @@ -657,6 +657,11 @@ manifest: '*': missing_feature (Not yet implemented) poc: v3.44.0 uds: v3.44.0 + ? tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Method_Capture_Expressions::test_complex_capture_expressions_dictionary_value + : - weblog_declaration: + '*': missing_feature (Not yet implemented) + poc: v3.44.0 + uds: v3.44.0 tests/debugger/test_debugger_capture_expressions_errors.py::Test_Debugger_Filter_Rejected_Capture_Expression_Error: # ProbeProcessor skips captureExpressions when `when` is false; #8725 rate-limits eval-error snapshots to 1/5min - weblog_declaration: '*': missing_feature (Not yet implemented) diff --git a/manifests/ruby.yml b/manifests/ruby.yml index 502a9a722ee..4114b7a5371 100644 --- a/manifests/ruby.yml +++ b/manifests/ruby.yml @@ -1898,6 +1898,8 @@ manifest: rails80: v2.38.0 uds-rails: v2.38.0 tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Method_Capture_Expressions::test_complex_capture_expressions: missing_feature (Local variable capture not implemented for method probes) + ? tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Method_Capture_Expressions::test_complex_capture_expressions_dictionary_value + : missing_feature (Local variable capture not implemented for method probes) ? tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Method_Capture_Expressions::test_method_local_capture_expressions : missing_feature (Local variable capture not implemented for method probes) ? tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Method_Capture_Expressions::test_method_parameter_capture_expressions From f907fa923734112c25ddb4c565bb9e206bbc2b56 Mon Sep 17 00:00:00 2001 From: "timothy.seemann" Date: Wed, 28 Oct 2026 15:21:19 -0400 Subject: [PATCH 7/9] [debugger] Grow the Go weblog test map past 8 keys to cover one-table map lookups --- utils/build/docker/golang/app/chi/debugger.go | 2 +- utils/build/docker/golang/app/echo/debugger.go | 2 +- utils/build/docker/golang/app/fiber-v2-orchestrion/debugger.go | 2 +- utils/build/docker/golang/app/gin/debugger.go | 2 +- utils/build/docker/golang/app/net-http-orchestrion/debugger.go | 2 +- utils/build/docker/golang/app/net-http-span-pool/debugger.go | 2 +- utils/build/docker/golang/app/net-http/debugger.go | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/utils/build/docker/golang/app/chi/debugger.go b/utils/build/docker/golang/app/chi/debugger.go index f02170c58cc..c4d0d409a3a 100644 --- a/utils/build/docker/golang/app/chi/debugger.go +++ b/utils/build/docker/golang/app/chi/debugger.go @@ -88,7 +88,7 @@ func newExpressionTestStruct() ExpressionTestStruct { StringValue: "one", BoolValue: true, Collection: []string{"one", "two", "three"}, - Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4}, + Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10}, } } diff --git a/utils/build/docker/golang/app/echo/debugger.go b/utils/build/docker/golang/app/echo/debugger.go index f02170c58cc..c4d0d409a3a 100644 --- a/utils/build/docker/golang/app/echo/debugger.go +++ b/utils/build/docker/golang/app/echo/debugger.go @@ -88,7 +88,7 @@ func newExpressionTestStruct() ExpressionTestStruct { StringValue: "one", BoolValue: true, Collection: []string{"one", "two", "three"}, - Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4}, + Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10}, } } diff --git a/utils/build/docker/golang/app/fiber-v2-orchestrion/debugger.go b/utils/build/docker/golang/app/fiber-v2-orchestrion/debugger.go index 37a36a8fb80..8d31c56a2ef 100644 --- a/utils/build/docker/golang/app/fiber-v2-orchestrion/debugger.go +++ b/utils/build/docker/golang/app/fiber-v2-orchestrion/debugger.go @@ -88,7 +88,7 @@ func newExpressionTestStruct() ExpressionTestStruct { StringValue: "one", BoolValue: true, Collection: []string{"one", "two", "three"}, - Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4}, + Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10}, } } diff --git a/utils/build/docker/golang/app/gin/debugger.go b/utils/build/docker/golang/app/gin/debugger.go index f02170c58cc..c4d0d409a3a 100644 --- a/utils/build/docker/golang/app/gin/debugger.go +++ b/utils/build/docker/golang/app/gin/debugger.go @@ -88,7 +88,7 @@ func newExpressionTestStruct() ExpressionTestStruct { StringValue: "one", BoolValue: true, Collection: []string{"one", "two", "three"}, - Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4}, + Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10}, } } diff --git a/utils/build/docker/golang/app/net-http-orchestrion/debugger.go b/utils/build/docker/golang/app/net-http-orchestrion/debugger.go index f02170c58cc..c4d0d409a3a 100644 --- a/utils/build/docker/golang/app/net-http-orchestrion/debugger.go +++ b/utils/build/docker/golang/app/net-http-orchestrion/debugger.go @@ -88,7 +88,7 @@ func newExpressionTestStruct() ExpressionTestStruct { StringValue: "one", BoolValue: true, Collection: []string{"one", "two", "three"}, - Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4}, + Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10}, } } diff --git a/utils/build/docker/golang/app/net-http-span-pool/debugger.go b/utils/build/docker/golang/app/net-http-span-pool/debugger.go index 37a36a8fb80..8d31c56a2ef 100644 --- a/utils/build/docker/golang/app/net-http-span-pool/debugger.go +++ b/utils/build/docker/golang/app/net-http-span-pool/debugger.go @@ -88,7 +88,7 @@ func newExpressionTestStruct() ExpressionTestStruct { StringValue: "one", BoolValue: true, Collection: []string{"one", "two", "three"}, - Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4}, + Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10}, } } diff --git a/utils/build/docker/golang/app/net-http/debugger.go b/utils/build/docker/golang/app/net-http/debugger.go index f02170c58cc..c4d0d409a3a 100644 --- a/utils/build/docker/golang/app/net-http/debugger.go +++ b/utils/build/docker/golang/app/net-http/debugger.go @@ -88,7 +88,7 @@ func newExpressionTestStruct() ExpressionTestStruct { StringValue: "one", BoolValue: true, Collection: []string{"one", "two", "three"}, - Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4}, + Dictionary: map[string]int{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10}, } } From b269e840fcb15365dfdf7946a1438bb59c94dbe7 Mon Sep 17 00:00:00 2001 From: "timothy.seemann" Date: Wed, 28 Oct 2026 23:14:34 -0400 Subject: [PATCH 8/9] [debugger] Gate Go expression repros until supported --- manifests/golang.yml | 3 +++ .../test_debugger_go_expression_errors.py | 15 +++++---------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/manifests/golang.yml b/manifests/golang.yml index 879c6050c7e..d35d9153de1 100644 --- a/manifests/golang.yml +++ b/manifests/golang.yml @@ -1642,6 +1642,8 @@ manifest: tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Line_Capture_Expressions: v2.2.3 tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Method_Capture_Expressions: v2.2.3 tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Method_Capture_Expressions::test_complex_capture_expressions: missing_feature (index expression not yet supported in Go system-probe) + ? tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Method_Capture_Expressions::test_complex_capture_expressions_dictionary_value + : missing_feature (index expression not yet supported in Go system-probe) tests/debugger/test_debugger_capture_expressions_errors.py::Test_Debugger_Filter_Rejected_Capture_Expression_Error: missing_feature (Go DI rejects the probe, a condition leaf LHS may not be a literal) tests/debugger/test_debugger_code_origins.py::Test_Debugger_Code_Origins: missing_feature (feature not implemented) tests/debugger/test_debugger_condition_errors.py::Test_Debugger_Invalid_Condition_DSL: v2.2.3 @@ -1657,6 +1659,7 @@ manifest: tests/debugger/test_debugger_exception_replay.py::Test_Debugger_Exception_Replay::test_exception_replay_recursion_inlined: irrelevant (Test for specific bug in dotnet) tests/debugger/test_debugger_exception_replay.py::Test_Debugger_Exception_Replay::test_exception_replay_stackoverflow: missing_feature (Implemented only for dotnet) tests/debugger/test_debugger_expression_language.py::Test_Debugger_Expression_Language: missing_feature (feature not implemented) + tests/debugger/test_debugger_go_expression_errors.py::Test_Debugger_Go_Static_Template_Error: missing_feature (Go system-probe does not reject invalid log templates at install time) tests/debugger/test_debugger_guardrails.py::Test_Debugger_Capture_Timeout_Guardrail: incomplete_test_app (No /debugger/snapshot/capture-timeout endpoint) tests/debugger/test_debugger_guardrails.py::Test_Debugger_Evaluation_Timeout_Line_Probe: irrelevant (Line-probe variant is only used by Node.js and Ruby) tests/debugger/test_debugger_guardrails.py::Test_Debugger_Evaluation_Timeout_Method_Probe: missing_feature (Debugger evaluation timeout guardrail not implemented yet) diff --git a/tests/debugger/test_debugger_go_expression_errors.py b/tests/debugger/test_debugger_go_expression_errors.py index aeb4c1eef62..b3fc18a6fe5 100644 --- a/tests/debugger/test_debugger_go_expression_errors.py +++ b/tests/debugger/test_debugger_go_expression_errors.py @@ -33,12 +33,7 @@ def setup_static_template_error_probe_rejected(self) -> None: self._setup_probes("probe_static_template_error", ["INSTALLED", "ERROR"]) def test_static_template_error_probe_rejected(self) -> None: - """Each template references something the system-probe resolves at install time and can't find. - - A member access on a ``map[string]int``, an unknown variable, and a missing struct field are all - rejected with an ERROR diagnostic when used in a ``when`` condition. In a log template they must also - reach status=ERROR, not stay installed and print the error inline. - """ + """Reject log templates with an invalid map member, unknown variable, or missing struct field.""" self.collect() self.assert_setup_ok() @@ -61,14 +56,14 @@ def setup_missing_map_key_condition_does_not_fire(self) -> None: self._setup_probes("probe_missing_map_key_condition", ["INSTALLED"]) def test_missing_map_key_condition_does_not_fire(self) -> None: - """``testStruct.Dictionary['nope'] == 1``: in Go a missing key reads as 0, so the condition is false. - - A conforming tracer emits nothing, or an error-only snapshot without captured data. - """ + """A missing Go map key reads as 0, so this condition must not capture data.""" self.collect() self.assert_setup_ok() for probe_id in self.probe_ids: + diag = self.probe_diagnostics.get(probe_id) + assert diag is not None, f"Probe {probe_id} received no install diagnostic" + assert diag["status"] in ("INSTALLED", "EMITTING"), f"Probe {probe_id} did not install: {diag['status']!r}" for envelope in self.probe_snapshots.get(probe_id, []): snap = envelope.get("debugger", {}).get("snapshot") or envelope.get("debugger.snapshot") or {} assert not debugger.captures_contain_data(snap.get("captures")), ( From 8cf37247f51b1181250de1458b5ea6a2d06cf3dd Mon Sep 17 00:00:00 2001 From: "timothy.seemann" Date: Wed, 28 Oct 2026 23:31:07 -0400 Subject: [PATCH 9/9] [debugger] Run the Go map and template repros so CI shows the failures --- manifests/golang.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/manifests/golang.yml b/manifests/golang.yml index d35d9153de1..879c6050c7e 100644 --- a/manifests/golang.yml +++ b/manifests/golang.yml @@ -1642,8 +1642,6 @@ manifest: tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Line_Capture_Expressions: v2.2.3 tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Method_Capture_Expressions: v2.2.3 tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Method_Capture_Expressions::test_complex_capture_expressions: missing_feature (index expression not yet supported in Go system-probe) - ? tests/debugger/test_debugger_capture_expressions.py::Test_Debugger_Method_Capture_Expressions::test_complex_capture_expressions_dictionary_value - : missing_feature (index expression not yet supported in Go system-probe) tests/debugger/test_debugger_capture_expressions_errors.py::Test_Debugger_Filter_Rejected_Capture_Expression_Error: missing_feature (Go DI rejects the probe, a condition leaf LHS may not be a literal) tests/debugger/test_debugger_code_origins.py::Test_Debugger_Code_Origins: missing_feature (feature not implemented) tests/debugger/test_debugger_condition_errors.py::Test_Debugger_Invalid_Condition_DSL: v2.2.3 @@ -1659,7 +1657,6 @@ manifest: tests/debugger/test_debugger_exception_replay.py::Test_Debugger_Exception_Replay::test_exception_replay_recursion_inlined: irrelevant (Test for specific bug in dotnet) tests/debugger/test_debugger_exception_replay.py::Test_Debugger_Exception_Replay::test_exception_replay_stackoverflow: missing_feature (Implemented only for dotnet) tests/debugger/test_debugger_expression_language.py::Test_Debugger_Expression_Language: missing_feature (feature not implemented) - tests/debugger/test_debugger_go_expression_errors.py::Test_Debugger_Go_Static_Template_Error: missing_feature (Go system-probe does not reject invalid log templates at install time) tests/debugger/test_debugger_guardrails.py::Test_Debugger_Capture_Timeout_Guardrail: incomplete_test_app (No /debugger/snapshot/capture-timeout endpoint) tests/debugger/test_debugger_guardrails.py::Test_Debugger_Evaluation_Timeout_Line_Probe: irrelevant (Line-probe variant is only used by Node.js and Ruby) tests/debugger/test_debugger_guardrails.py::Test_Debugger_Evaluation_Timeout_Method_Probe: missing_feature (Debugger evaluation timeout guardrail not implemented yet)