Coverage for snekql/structured_logging.py: 100%
22 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-07 21:13 +0300
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-07 21:13 +0300
1"""Structured logging contracts for snekql runtime observability."""
3from __future__ import annotations
5import contextlib
6from typing import Protocol
9class StructuredLogger(Protocol):
10 """Structured logger accepted by the Query Runtime.
12 Any logger with structlog-style methods satisfies this protocol:
14 >>> class AppLogger:
15 ... def debug(self, event: str, **fields: object) -> object:
16 ... return None
17 ... def info(self, event: str, **fields: object) -> object:
18 ... return None
19 ... def warning(self, event: str, **fields: object) -> object:
20 ... return None
21 ... def error(self, event: str, **fields: object) -> object:
22 ... return None
23 >>> logger: StructuredLogger = AppLogger()
24 >>> logger.debug("query executed", sql="SELECT 1", params=())
25 """
27 def debug(self, event: str, **fields: object) -> object: ...
29 def info(self, event: str, **fields: object) -> object: ...
31 def warning(self, event: str, **fields: object) -> object: ...
33 def error(self, event: str, **fields: object) -> object: ...
36class ResolvedStructuredLogger(Protocol):
37 """Internal logger shape after snekql wraps application loggers."""
39 def debug(self, event: str, **fields: object) -> None: ...
41 def info(self, event: str, **fields: object) -> None: ...
43 def warning(self, event: str, **fields: object) -> None: ...
45 def error(self, event: str, **fields: object) -> None: ...
48class _SafeStructuredLogger:
49 """Best-effort logger wrapper that keeps observability out of control flow."""
51 def __init__(self, *, logger: StructuredLogger) -> None:
52 self.logger: StructuredLogger = logger
54 def debug(self, event: str, **fields: object) -> None:
55 with contextlib.suppress(Exception):
56 _ = self.logger.debug(event, **fields)
58 def info(self, event: str, **fields: object) -> None:
59 with contextlib.suppress(Exception):
60 _ = self.logger.info(event, **fields)
62 def warning(self, event: str, **fields: object) -> None:
63 with contextlib.suppress(Exception):
64 _ = self.logger.warning(event, **fields)
66 def error(self, event: str, **fields: object) -> None:
67 with contextlib.suppress(Exception):
68 _ = self.logger.error(event, **fields)
71def resolve_structured_logger(
72 *,
73 logger: StructuredLogger,
74) -> ResolvedStructuredLogger:
75 """Return a safe structured logger for runtime internals.
77 snekql treats logging as best-effort observability. A user logger failure
78 should not change Database, Transaction, or query execution behavior.
79 """
81 return _SafeStructuredLogger(logger=logger)