fix: console handler writes to stdout, not stderr

console=True now binds sys.stdout explicitly (was the stdlib StreamHandler
stderr default), so a supervisor capturing stdout sees console log lines.
console stays off by default (file is the primary sink). docs corrected to
stdout.

Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
2026-07-03 16:31:51 -04:00
parent 6fb245f690
commit 17d1d20865
4 changed files with 12 additions and 8 deletions
+9 -5
View File
@@ -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.6.2
log_setup @ git+ssh://git@git.rethinkstudios.io/rethink-public/log_setup.git@v0.6.3
```
No dependencies — stdlib only.
Drop the `@v0.6.2` suffix from the line above to install the latest unpinned.
Drop the `@v0.6.3` suffix from the line above to install the latest unpinned.
## Quick start
@@ -29,7 +29,7 @@ from log_setup import setup_logging
setup_logging(name="run", level="INFO") # daily rotation, logs/ dir, gzip (file only)
log = logging.getLogger(__name__)
log.info("started") # -> ./run.log (add console=True for stderr too)
log.info("started") # -> ./run.log (add console=True for stdout too)
```
Call it once, at the app's entry point — before the rest of the app runs. Every module
@@ -57,7 +57,7 @@ emits; the records land in the configured root.
- **Retention** = `backup_count` (default 14) for every mode — unless tiered retention is
enabled (below). For `rotate="size"`, `backup_count=0` is "keep none" (not "disable
rotation") — see the `size` bullet above and the note at the bottom of this section.
- **console=True** (off by default) also logs to stderr in the same format — opt in when
- **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
@@ -174,7 +174,7 @@ setup_logging(
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 stderr (off by default; opt in)
console=False, # also log to stdout (off by default; opt in)
queue=False, # route through a background QueueListener (async-friendly)
output="text", # "text" (human, local time) | "json" (structured, UTC)
fmt=None, # override the text format string (text mode only)
@@ -248,6 +248,10 @@ setup_logging(name="run", queue=True)
documented (keeps that many rolled files). This does not change `"daily"`/`"on_start"`,
where `backup_count=0` still means "roll, but don't prune the rolled files" (unbounded
`log_dir` growth) — that is a separate, pre-existing knob, not this fix's scope.
- **`console=True` writes to stdout (v0.6.3).** the console handler now binds `sys.stdout`
explicitly instead of the stdlib `StreamHandler` default of `sys.stderr`, so a supervisor
capturing stdout sees console log lines. `console` stays off by default — the file is the
primary sink.
- **`"daily"` regression fixed (v0.6.2).** v0.5.1's `rotate="size"` fix above shared its
rotator with `"daily"`, so a `rotate="daily", backup_count=0` roll was incorrectly
deleted at every midnight rollover instead of just landing unpruned. The rotator is now