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:
2026-09-16 02:16:58 +00:00
parent 7a7716ec7b
commit a41f34d332
8 changed files with 49 additions and 36 deletions
+2 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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):