diff --git a/docs/database.md b/docs/database.md index 60ffa39..fb99602 100644 --- a/docs/database.md +++ b/docs/database.md @@ -235,6 +235,9 @@ def resolve_user_key(value: str) -> str | None: `kanta` instance, and all relevant state: `action`, `user`, `extra`, `error` (for aborted transactions), `diff`, `previous`/`current` state dicts, the built `logfmt` chain, and version info for migration events. + Application-specific context (e.g. a connection id) can be stored in + `kanta.ctx` — a user-writable namespace — and read back in callbacks as + `event.kanta.ctx`, which also covers creation/bootstrap events. - The built-in formatting is assembled from standard blocks that custom emitters can reuse as-is or replace piecemeal: - `event.header` — a lazy property producing the default one-line header diff --git a/kanta/kanta.py b/kanta/kanta.py index 3c42a71..9422977 100644 --- a/kanta/kanta.py +++ b/kanta/kanta.py @@ -130,7 +130,10 @@ class Kanta(Generic[T]): """User-writable context namespace. Migration functions receive the ``Kanta`` instance and can read or - mutate ``kanta.ctx`` during migrations. + mutate ``kanta.ctx`` during migrations. Applications can also store + arbitrary data here (e.g. a connection id); since + :class:`kanta.logging.LogEvent` carries the Kanta instance, logemit + callbacks can read it as ``event.kanta.ctx``. """ return self._impl.ctx diff --git a/tests/test_logemit.py b/tests/test_logemit.py index a4218e7..9bca8a5 100644 --- a/tests/test_logemit.py +++ b/tests/test_logemit.py @@ -344,3 +344,18 @@ def test_header_is_settable_and_used_by_default_emit(capsys): err = capsys.readouterr().err assert "CUSTOM update" in err assert "counter" in err # default diff routing still applies + + +@pytest.mark.asyncio +async def test_ctx_reachable_from_event(tmp_path, format_config): + path = tmp_path / "test.db" + kanta = make_kanta(path, Data, format_config) + kanta.ctx.connection_id = 7 + seen = [] + kanta.logemit(lambda ev: seen.append(ev.kanta.ctx.connection_id) or True) + await kanta.open() + with kanta.transaction(action="inc") as data: + data.counter = 1 + await kanta.close() + + assert seen and all(connection_id == 7 for connection_id in seen)