Skip to content

bugsnag: emit slice_name from service_name in custom metadata tab#267

Open
morgan-wowk wants to merge 1 commit into
bugsnag-error-chainfrom
bugsnag/service-slice
Open

bugsnag: emit slice_name from service_name in custom metadata tab#267
morgan-wowk wants to merge 1 commit into
bugsnag-error-chainfrom
bugsnag/service-slice

Conversation

@morgan-wowk

@morgan-wowk morgan-wowk commented May 28, 2026

Copy link
Copy Markdown
Collaborator

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.

morgan-wowk commented May 28, 2026

Copy link
Copy Markdown
Collaborator Author

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.
Learn more

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.
@morgan-wowk morgan-wowk force-pushed the bugsnag-error-chain branch from afad13f to 563c451 Compare June 3, 2026 19:22
@morgan-wowk morgan-wowk force-pushed the bugsnag/service-slice branch from abe0fb0 to 4730f88 Compare June 3, 2026 19:22
global _setup_called
global _setup_called, _service_name
_setup_called = True
_service_name = service_name

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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"})

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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 == []

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants