Implement richer, fully customizable logging; customizable timestamps (#1)

- `@kanta.logemit` handler for completely customizable logging output, with `LogEvent` structure and `kanta.tty.Line` helper to create colorized text and fixed width fields
- `configure_logging(diff=False)` to disable diff display globally (supplementing per-transaction `logdiff=False`)
- `transaction(extra: Any = ...)` for passing extra strings or custom metadata to logs
- `@kanta.clock` to provide user controlled clock for deterministic database outputs
- Added a demo script that shows basic functions, migrations, logfmt etc.
This commit was merged in pull request #1.
This commit is contained in:
2026-08-07 17:08:28 +01:00
parent 9c0b47ce38
commit 3074f8d8b0
17 changed files with 1587 additions and 127 deletions
+70 -2
View File
@@ -2,16 +2,39 @@ import logging
import pytest
from kanta.logging import configure_logging, log_change, transaction_logger
from kanta.logging import (
configure_logging,
format_action_header,
log_change,
)
from kanta.tty import ESC
def test_format_action_header():
header = format_action_header("update", "alice", "tgt")
assert header == (
f"{ESC}1;34mupdate{ESC}0m {ESC}38;5;250mtgt{ESC}0m by {ESC}34malice{ESC}0m"
)
def test_format_action_header_action_only():
assert format_action_header("update") == f"{ESC}1;34mupdate{ESC}0m"
@pytest.fixture(autouse=True)
def _reset_kanta_loggers():
yield
for name in ("kanta", "kanta.transaction", "kanta.bootstrap", "kanta.migration"):
for name in (
"kanta",
"kanta.transaction",
"kanta.transaction.diff",
"kanta.bootstrap",
"kanta.migration",
):
logger = logging.getLogger(name)
logger.setLevel(logging.NOTSET)
logger.propagate = True
logger.disabled = False
logger.handlers.clear()
@@ -46,3 +69,48 @@ def test_log_change_no_diff(capsys):
log_change("test", {})
captured = capsys.readouterr()
assert "test" in captured.err
def test_log_change_appends_extra_string(capsys):
kanta_logger = logging.getLogger("kanta")
kanta_logger.handlers.clear()
configure_logging()
log_change("export", {}, extra="mydb.db")
captured = capsys.readouterr()
assert "export" in captured.err
assert f"{ESC}38;5;250mmydb.db{ESC}0m" in captured.err
def test_log_change_log_diff_false(capsys, monkeypatch):
kanta_logger = logging.getLogger("kanta")
kanta_logger.handlers.clear()
configure_logging()
def _boom(*args, **kwargs):
raise AssertionError("format_diff should not be called")
monkeypatch.setattr("kanta.logging.format_diff", _boom)
log_change("update", {"counter": 5}, previous={}, log_diff=False)
captured = capsys.readouterr()
assert "update" in captured.err
assert "counter" not in captured.err
def test_configure_logging_diff_false(capsys):
kanta_logger = logging.getLogger("kanta")
kanta_logger.handlers.clear()
configure_logging(diff=False)
log_change("update", {"counter": 5}, previous={})
captured = capsys.readouterr()
assert "update" in captured.err
assert "counter" not in captured.err
def test_configure_logging_diff_true_reenables(capsys):
kanta_logger = logging.getLogger("kanta")
kanta_logger.handlers.clear()
configure_logging(diff=False)
configure_logging(diff=True)
log_change("update", {"counter": 5}, previous={})
captured = capsys.readouterr()
assert "counter" in captured.err