From ece9a6b9cab181f16c90788eb90060dfcaf844bb Mon Sep 17 00:00:00 2001 From: disqualifier Date: Tue, 30 Jun 2026 03:49:35 -0400 Subject: [PATCH] fix: retention dead when name contains a directory (basename the stem) rolled files land in log_dir under their basename (the namer/rotate_on_start basename them), but prune()/retier() globbed the un-basenamed name. a name like 'sub/run' matched nothing, so old .log/.gz files piled up forever (slow disk leak; the live file was fine). basename the stem at the top of both prune() and retier(). regression-verified with name='sub/run' (10 retained vs 12/dead before). bump v0.4.0 -> v0.4.1 Signed-off-by: disqualifier --- README.md | 4 ++-- pyproject.toml | 2 +- src/log_setup/__init__.py | 2 +- src/log_setup/rotation.py | 11 +++++++++++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e446a36..b61f73d 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,12 @@ and emit; their records flow into the handlers `log_setup` wired. ## Install ``` -log_setup @ git+ssh://git@git.rethinkstudios.io/rethink-public/log_setup.git@v0.4.0 +log_setup @ git+ssh://git@git.rethinkstudios.io/rethink-public/log_setup.git@v0.4.1 ``` No dependencies — stdlib only. -Drop the `@v0.4.0` suffix from the line above to install the latest unpinned. +Drop the `@v0.4.1` suffix from the line above to install the latest unpinned. ## Quick start diff --git a/pyproject.toml b/pyproject.toml index 55a1372..ac9062e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "log_setup" -version = "0.4.0" +version = "0.4.1" description = "stdlib app-entry-point logging setup: live run.log, rotation, gzip, retention, consistent format" requires-python = ">=3.10" dependencies = [] diff --git a/src/log_setup/__init__.py b/src/log_setup/__init__.py index 38e8eff..1cdf4c8 100644 --- a/src/log_setup/__init__.py +++ b/src/log_setup/__init__.py @@ -19,4 +19,4 @@ from .setup import setup_logging __all__ = ["setup_logging"] -__version__ = "0.4.0" +__version__ = "0.4.1" diff --git a/src/log_setup/rotation.py b/src/log_setup/rotation.py index 9db12d0..a5e8108 100644 --- a/src/log_setup/rotation.py +++ b/src/log_setup/rotation.py @@ -154,7 +154,13 @@ def retier(log_dir: str, stem: str, keep_uncompressed: int, keep_compressed: int to .gz and the plain source removed), and everything beyond keep_uncompressed+keep_compressed is deleted. the live .log is never touched. fail-soft per file (skip on OSError) so retention never crashes setup. + + `stem` is reduced to its basename: rolled files land in log_dir under the basename + (the namer/rotate_on_start basename them), so a `name` containing a directory (e.g. + "sub/run") must be matched by "run." here or nothing matches and retention silently + never fires (unbounded pileup). """ + stem = os.path.basename(stem) try: names = [ name for name in os.listdir(log_dir) @@ -188,9 +194,14 @@ def prune(log_dir: str, stem: str, backup_count: int) -> None: matches files beginning with `.` (e.g. run.*), sorted by mtime, deleting the oldest beyond the count. used for on_start, which the handlers don't auto-prune. + + `stem` is reduced to its basename so a `name` containing a directory (e.g. "sub/run") + still matches the basenamed rolled files in log_dir (else nothing matches and old + files pile up forever). """ if backup_count <= 0: return + stem = os.path.basename(stem) try: entries = [ os.path.join(log_dir, name)