feat: tiered restart/retention (keep_uncompressed/keep_compressed) + name normalize
- keep_uncompressed/keep_compressed: newest N rolled logs plain, next M gzipped, rest deleted. applies to on_start/daily/size. opt-in by knob presence; without them the legacy backup_count + gzip-on-roll path is unchanged (existing consumers unaffected). - _normalize_name: 'latest' and 'latest.log' both -> live latest.log (no .log.log). - _gzip_file preserves source mtime (stable tier ordering across re-tiers). - rotate_on_start collision counter checks both .log and .log.gz (no duplicate logical roll when a same-stamp file was already compressed). execute-verified stdlib-only incl. a back-compat control proving the no-knobs path is unchanged. bump v0.3.2 -> v0.4.0 Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
@@ -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.3.2
|
||||
log_setup @ git+ssh://git@git.rethinkstudios.io/rethink-public/log_setup.git@v0.4.0
|
||||
```
|
||||
|
||||
No dependencies — stdlib only.
|
||||
|
||||
Drop the `@v0.3.2` suffix from the line above to install the latest unpinned.
|
||||
Drop the `@v0.4.0` suffix from the line above to install the latest unpinned.
|
||||
|
||||
## Quick start
|
||||
|
||||
@@ -50,10 +50,49 @@ emits; the records land in the configured root.
|
||||
(`run.<timestamp>.log[.gz]`) and starts fresh; prunes to `backup_count`.
|
||||
- `None` — single file, no rotation.
|
||||
- **compress=True** (default) gzips each rolled file (`run.log.2026-06-27.gz`).
|
||||
- **Retention** = `backup_count` (default 14) for every mode.
|
||||
- **Retention** = `backup_count` (default 14) for every mode — unless tiered retention is
|
||||
enabled (below).
|
||||
- **console=True** (off by default) also logs to stdout in the same format — opt in when
|
||||
you want live terminal output alongside the file.
|
||||
|
||||
The `name` you pass is normalized so it produces exactly one `.log`: `name="latest"` and
|
||||
`name="latest.log"` both yield the live file `latest.log` (never `latest.log.log`).
|
||||
|
||||
## Tiered retention (`keep_uncompressed` / `keep_compressed`)
|
||||
|
||||
The default is a flat `backup_count`: every rolled file is gzipped on roll and the oldest
|
||||
are deleted past the count. If instead you want the recent logs **uncompressed** (read them
|
||||
without `zcat`) and older ones **gzipped**, pass the two tier knobs:
|
||||
|
||||
```python
|
||||
setup_logging(
|
||||
name="latest",
|
||||
rotate="on_start", # works for on_start, daily, and size
|
||||
keep_uncompressed=3, # newest 3 rolled logs kept PLAIN
|
||||
keep_compressed=7, # next 7 kept GZIPPED; total retained = 10
|
||||
)
|
||||
```
|
||||
|
||||
Result in `log_dir` (newest → oldest):
|
||||
|
||||
```
|
||||
latest.log <- live "latest" (stable, tail -f)
|
||||
latest.<t1>.log latest.<t2>.log latest.<t3>.log <- 3 newest: plain
|
||||
latest.<t4>.log.gz ... latest.<t10>.log.gz <- next 7: gzipped
|
||||
(anything past 10 deleted)
|
||||
```
|
||||
|
||||
- Each restart (`on_start`) or roll (`daily`/`size`) moves the live file into `log_dir`,
|
||||
then re-tiers: newest `keep_uncompressed` stay plain, the next `keep_compressed` are
|
||||
gzipped in place, the rest deleted. Total kept = `keep_uncompressed + keep_compressed`.
|
||||
- **Opt-in by presence** — pass either knob to enable tiering. Pass **neither** and
|
||||
rotation behaves exactly as before (`backup_count` + gzip-on-roll), so existing callers
|
||||
are unaffected.
|
||||
- In tiered mode `backup_count` and the gzip-on-roll behavior of `compress` are **ignored**
|
||||
— the tier counts bound retention instead.
|
||||
- `keep_uncompressed=0` → everything gzipped; `keep_compressed=0` → only the plain tier.
|
||||
Retention is count-based (not time-based).
|
||||
|
||||
## Output format (`output=`)
|
||||
|
||||
Two formats, two needs. Default is `"text"`; the live-file name is the same either way
|
||||
@@ -94,7 +133,9 @@ setup_logging(
|
||||
level="INFO", # root level everything inherits (str name or logging constant)
|
||||
module_levels=None, # {logger_name: level} per-logger overrides (exact name match)
|
||||
rotate="daily", # "daily" | "size" | "on_start" | None
|
||||
backup_count=14, # rotated files to keep (older auto-deleted)
|
||||
backup_count=14, # rotated files to keep (flat retention; ignored if tiered)
|
||||
keep_uncompressed=None, # tiered: newest N rolled logs kept PLAIN (opt-in)
|
||||
keep_compressed=None, # tiered: next M rolled logs kept GZIPPED (opt-in)
|
||||
max_bytes=10_000_000, # only for rotate="size"
|
||||
compress=True, # gzip rolled files
|
||||
console=False, # also log to stdout (off by default; opt in)
|
||||
|
||||
Reference in New Issue
Block a user