Route all diagnostic logging through the plain "kanta" logger.
Module loggers used __name__, splitting diagnostics across eight module-named loggers and colliding kanta.transaction with the transaction event channel. Diagnostics (integrity errors, flush failures, rotation notes) are few; they now all go through the "kanta" logger, following the application's root logging configuration like any ordinary library output.
This commit is contained in:
+2
-6
@@ -17,7 +17,7 @@ from typing import Any
|
||||
import msgspec
|
||||
|
||||
from kanta import Kanta
|
||||
from kanta.callbacks import InjectionContext
|
||||
from kanta.callbacks import InjectionContext, callback_error_reporter
|
||||
from kanta.exceptions import DatabaseError, DataIntegrityError, ReplayError
|
||||
from kanta.grep import GrepPattern, evaluate
|
||||
from kanta.logging import (
|
||||
@@ -50,8 +50,6 @@ EXIT_PARSE_ERROR = 10
|
||||
EXIT_MIGRATION_ERROR = 20
|
||||
EXIT_VALIDATION_ERROR = 21
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _print(*args: Any) -> None:
|
||||
"""Print to stderr, stripping ANSI codes when the stream has no color support.
|
||||
@@ -408,13 +406,11 @@ async def _log_migration(
|
||||
"""
|
||||
registry = kanta._impl.callback_registry
|
||||
if registry.has("logmigr"):
|
||||
try:
|
||||
await registry.invoke(
|
||||
"logmigr",
|
||||
InjectionContext(kanta=kanta, report=result),
|
||||
on_error=callback_error_reporter("logmigr"),
|
||||
)
|
||||
except Exception:
|
||||
_logger.exception("logmigr callback failed")
|
||||
return
|
||||
if quiet:
|
||||
return
|
||||
|
||||
+32
-2
@@ -54,7 +54,37 @@ def _state_tag(ann: Any) -> str | None:
|
||||
return None
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
_logger = logging.getLogger("kanta")
|
||||
|
||||
|
||||
def describe_callback(callback: Callable[..., Any]) -> str:
|
||||
"""Return ``name (docstring first line)`` identifying *callback*.
|
||||
|
||||
Used in failure messages so a bare log line names the function that
|
||||
failed, e.g. ``myformatter (Concise log formatter)``.
|
||||
"""
|
||||
name = getattr(callback, "__name__", None) or type(callback).__name__
|
||||
doc = inspect.getdoc(callback)
|
||||
if doc:
|
||||
return f"{name} ({doc.splitlines()[0]})"
|
||||
return name
|
||||
|
||||
|
||||
def callback_error_reporter(
|
||||
kind: str,
|
||||
) -> Callable[[Exception, Callable[..., Any]], None]:
|
||||
"""Return an ``on_error`` reporter for :meth:`CallbackRegistry.invoke`.
|
||||
|
||||
The returned callable logs ``Kanta.<kind> <name (docstring)> failed:
|
||||
<error>`` for each failing callback; invoke continues with the rest.
|
||||
"""
|
||||
|
||||
def _report(callback_error: Exception, callback: Callable[..., Any]) -> None:
|
||||
_logger.exception(
|
||||
"Kanta.%s %s failed: %s", kind, describe_callback(callback), callback_error
|
||||
)
|
||||
|
||||
return _report
|
||||
|
||||
|
||||
class LogFmt:
|
||||
@@ -281,7 +311,7 @@ class CallbackRegistry:
|
||||
except Exception:
|
||||
# Formatting must never break functionality; a failing
|
||||
# callback is reported and treated as a fall-through.
|
||||
_logger.exception("logfmt callback %r failed", fn)
|
||||
_logger.exception("Kanta.logfmt %s failed", describe_callback(fn))
|
||||
continue
|
||||
if resolved is not None:
|
||||
return resolved
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ from pathlib import Path
|
||||
|
||||
from kanta.exceptions import FileLockError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
_logger = logging.getLogger("kanta")
|
||||
|
||||
|
||||
def _fatal(msg: str, *, db_path: Path | None = None) -> None:
|
||||
|
||||
+3
-8
@@ -10,7 +10,7 @@ from datetime import UTC, datetime, timedelta
|
||||
from types import SimpleNamespace
|
||||
from typing import Any, Generic, TypeVar
|
||||
|
||||
from kanta.callbacks import CallbackRegistry, InjectionContext
|
||||
from kanta.callbacks import CallbackRegistry, InjectionContext, callback_error_reporter
|
||||
from kanta.exceptions import DatabaseError, DataIntegrityError, ReplayError
|
||||
from kanta.logging import (
|
||||
_USER_PATH,
|
||||
@@ -25,16 +25,11 @@ from kanta.rotation import execute_rotation, plan_rotation
|
||||
from kanta.serialization import restore_data_in_place, struct_to_dict
|
||||
from kanta.serialization.base import replay
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
_logger = logging.getLogger("kanta")
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def _log_callback_error(callback_error, callback):
|
||||
"""Report a failing logging callback and continue with the next one."""
|
||||
_logger.exception("Log callback %r failed: %s", callback, callback_error)
|
||||
|
||||
|
||||
class KantaImpl(PersistenceMixin, Generic[T]):
|
||||
"""Internal state and logic for Kanta."""
|
||||
|
||||
@@ -119,7 +114,7 @@ class KantaImpl(PersistenceMixin, Generic[T]):
|
||||
kanta=self._kanta,
|
||||
report=report,
|
||||
),
|
||||
on_error=_log_callback_error,
|
||||
on_error=callback_error_reporter("logmigr"),
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
+3
-11
@@ -12,7 +12,7 @@ from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from kanta.callbacks import CallbackRegistry, InjectionContext
|
||||
from kanta.callbacks import CallbackRegistry, InjectionContext, callback_error_reporter
|
||||
from kanta.diff import diff
|
||||
from kanta.exceptions import DatabaseError, DataIntegrityError
|
||||
from kanta.filelock import LockedFile
|
||||
@@ -21,7 +21,7 @@ from kanta.serialization import JsonSerializer, Serializer
|
||||
from kanta.serialization.framing import Framer
|
||||
from kanta.snapshot import SnapshotState
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
_logger = logging.getLogger("kanta")
|
||||
|
||||
|
||||
class PersistenceMixin:
|
||||
@@ -110,18 +110,10 @@ class PersistenceMixin:
|
||||
break
|
||||
except DatabaseError as e:
|
||||
self.background_error = e
|
||||
|
||||
def _log_callback_error(callback_error, callback):
|
||||
_logger.exception(
|
||||
"Background error callback %r failed: %s",
|
||||
callback,
|
||||
callback_error,
|
||||
)
|
||||
|
||||
await self.callback_registry.invoke(
|
||||
"fatal_error",
|
||||
InjectionContext(error=e, kanta=self._kanta),
|
||||
on_error=_log_callback_error,
|
||||
on_error=callback_error_reporter("fatal_error"),
|
||||
)
|
||||
_logger.error("Background flush loop stopped: %s", e)
|
||||
break
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ from kanta.structs import ChangeRecord, Snapshot
|
||||
from kanta.serialization.base import Serializer, apply_diff
|
||||
from kanta.serialization.framing import Framer
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
_logger = logging.getLogger("kanta")
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
+2
-2
@@ -10,7 +10,7 @@ from kanta.structs import Snapshot
|
||||
from kanta.serialization import JsonSerializer, Serializer
|
||||
from kanta.serialization.framing import Framer, LineFramer
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
_logger = logging.getLogger("kanta")
|
||||
|
||||
MINDIFFS = 100
|
||||
|
||||
@@ -69,7 +69,7 @@ class SnapshotState:
|
||||
self._write(file, version, state, ts, m=m)
|
||||
self._force_pending = False
|
||||
except Exception as exc:
|
||||
_logger.error("snapshot: failed to write snapshot: %r", exc)
|
||||
_logger.error("Kanta snapshot failed: %r", exc)
|
||||
|
||||
def _write(
|
||||
self, file, version: int, state: dict, now: datetime, m: datetime | None = None
|
||||
|
||||
@@ -13,7 +13,7 @@ from kanta.callbacks import InjectionContext
|
||||
from kanta.logging import _USER_PATH, LogEvent, emit_event, transaction_logger
|
||||
from kanta.serialization import restore_data_in_place, struct_to_dict
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
_logger = logging.getLogger("kanta")
|
||||
|
||||
|
||||
def _build_logfmt(impl, previous: dict, current: dict):
|
||||
|
||||
Reference in New Issue
Block a user