"""Single entry point for writing :class:`AuditLog` rows. ``log()`` is fire-and-forget: it awaits the DB write so callers get ordering, but never raises — failures are logged and swallowed. """ from __future__ import annotations import logging from typing import TYPE_CHECKING, Any from beaver_gateway.storage import append_audit if TYPE_CHECKING: from beaver_gateway.frontends.base import GatewayRuntime _log = logging.getLogger("beaver_gateway.audit") KNOWN_KINDS: frozenset[str] = frozenset( { "messages", "mcp_call", "tool_call", "login_ok", "login_failed", "logout", "token_create", "token_revoke", } ) """Kinds the gateway currently emits; ``AuditLog.kind`` stays free-form.""" async def log( runtime: GatewayRuntime, *, actor: str, kind: str, agent_name: str | None = None, **detail: Any, ) -> None: """Best-effort audit insert. Never raises; DB failures are logged. ``actor`` is free-form (``"token:"``, ``"admin:"``, ``"anon"``); ``kind`` is a short tag (see :data:`KNOWN_KINDS`); and ``**detail`` is JSON-serialised into ``AuditLog.detail_json`` — keep it small, not full request bodies. """ try: async with runtime.db.session() as session: await append_audit( session, actor=actor, kind=kind, agent_name=agent_name, detail=detail or None, ) except Exception: # noqa: BLE001 _log.exception( "audit write failed: actor=%s kind=%s agent=%s", actor, kind, agent_name ) __all__ = ["KNOWN_KINDS", "log"]