bugsnag: emit slice_name from service_name in custom metadata tab#267
bugsnag: emit slice_name from service_name in custom metadata tab#267morgan-wowk wants to merge 1 commit into
Conversation
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
Observe error analytics filters on custom.slice_name to assign errors to a slice. Store the service_name passed to setup() and write it as custom.slice_name on every event so errors from orchestrator, api, and metrics_poller each land in their own slice. Consolidates all custom tab writes into a single add_tab call.
afad13f to
563c451
Compare
abe0fb0 to
4730f88
Compare
| global _setup_called | ||
| global _setup_called, _service_name | ||
| _setup_called = True | ||
| _service_name = service_name |
There was a problem hiding this comment.
🤖 This is an AI-generated code review comment.
setup() docstring should mention the new slice_name side-effect.
service_name used to be only the SDK's project_root. After this PR it is also stored as module state and surfaced on every event as custom.slice_name. Callers reading the existing docstring won't know that picking the service_name string also affects Bugsnag custom metadata on every event going forward.
Fix: one-line addition to the Args docstring:
service_name: Identifies the process in Bugsnag (e.g. "tangle-api").
Also surfaced as `slice_name` in the "custom" metadata tab on every event.| prefix = (event.metadata.get("extra") or {}).get("grouping_prefix") | ||
| key_value = f"{prefix}: {chain}" if prefix else chain | ||
| event.add_tab("custom", {_CUSTOM_GROUPING_KEY: key_value}) | ||
| custom[_CUSTOM_GROUPING_KEY] = key_value |
There was a problem hiding this comment.
🤖 This is an AI-generated code review comment.
Silent key collision if operator sets TANGLE_BUGSNAG_CUSTOM_GROUPING_KEY=slice_name.
custom: dict[str, str] = {}
if _service_name:
custom["slice_name"] = _service_name
...
custom[_CUSTOM_GROUPING_KEY] = key_value # could overwrite "slice_name"_CUSTOM_GROUPING_KEY is operator-supplied via env var. If someone sets it to slice_name — perhaps not realizing the new key exists — the grouping value will silently overwrite the slice name and the tab will only contain one of them.
Fix: low-effort options:
- Warn at module load:
if _CUSTOM_GROUPING_KEY == "slice_name": _logger.warning(...)once, so the operator finds out. - Or prefix Tangle-owned custom keys (
tangle_slice_name) to make collisions almost impossible. - Or just document the reserved key in the env-var comment block at the top of the file.
|
|
||
| bugsnag_module._before_notify(mock_event) | ||
|
|
||
| mock_event.add_tab.assert_called_once_with("custom", {"slice_name": "orchestrator"}) |
There was a problem hiding this comment.
🤖 This is an AI-generated code review comment.
Missing negative-path test for service_name=None / no grouping key.
The new code has two paths: (a) _service_name set → emit slice_name, (b) _service_name None AND no grouping key → skip the entire add_tab("custom", ...) call thanks to the if custom: guard at the bottom of _before_notify. Path (a) is tested by this test; path (b) isn't pinned anywhere. A future refactor could silently start emitting an empty custom tab on every event without any test failing.
Fix: add a sibling test:
def test_before_notify_omits_custom_tab_when_no_service_name_and_no_grouping_key(monkeypatch):
monkeypatch.setenv("TANGLE_BUGSNAG_API_KEY", "test-api-key")
monkeypatch.delenv("TANGLE_BUGSNAG_CUSTOM_GROUPING_KEY", raising=False)
importlib.reload(bugsnag_module)
contextual_logging.clear_context_metadata()
with mock.patch("bugsnag.configure"), mock.patch("bugsnag.before_notify"):
bugsnag_module.setup(service_name=None)
mock_event = mock.MagicMock()
mock_event.original_error = None
mock_event.metadata = {}
bugsnag_module._before_notify(mock_event)
custom_calls = [c for c in mock_event.add_tab.call_args_list if c.args[0] == "custom"]
assert custom_calls == []
Some Bugsnag stacks filter on custom.slice_name to assign errors to
a slice. Store the service_name passed to setup() and write it as
custom.slice_name on every event so errors from orchestrator, api, and
metrics_poller each land in their own slice.
Consolidates all custom tab writes into a single add_tab call.