Log to stderr and stop discarding With attributes (closes #82)
All checks were successful
check / check (push) Successful in 4m20s
All checks were successful
check / check (push) Successful in 4m20s
Closes #97. internal/log attached both handlers to os.Stdout, so any record that was not suppressed landed in the middle of a --json document. WARN and ERROR are never suppressed, so this was not hypothetical: a config file with permissions looser than 0600 was enough to break `vaultik snapshot list --json | jq`. Both handlers now write to os.Stderr, and the TTY-vs-JSON format choice tests os.Stderr rather than os.Stdout - the format has to follow the stream the records land on, or a redirected stderr gets colorized whenever stdout happens to be a terminal. User-visible: --verbose and --debug output moves to stderr too, so `vaultik snapshot list -v > out.txt` no longer captures diagnostics. --quiet and --cron semantics are unchanged. TTYHandler.WithAttrs and WithGroup discarded their arguments and returned the receiver, while their doc comments claimed otherwise, so attributes passed through the exported log.With vanished. The effect was environment-dependent in the worst direction: handler choice is by TTY-ness, so attributes disappeared on a terminal - where a developer is debugging - and appeared correctly in CI. Both now return a new handler with copied state rather than mutating the receiver, since slog permits a handler to be shared and derived from concurrently. A test asserts the TTY and JSON handlers emit the same attribute set, which is the test that would have caught the original defect. The local workaround in snapshot_list.go is removed now that the logger no longer writes to stdout. The collect-then-emit machinery is kept, but for a different reason than it was added: emitting from the fetch workers would order warnings by network timing, whereas key-order emission after group.Wait() is deterministic run to run. Not yet complete: --json stdout still carries the startup banner, which internal/cli/entry.go writes before cobra parses and which bannerSuppressedInArgs does not recognise --json for. That is the remaining stdout contamination path and is tracked in #106.
This commit was merged in pull request #107.
This commit is contained in:
39
TODO.md
39
TODO.md
@@ -25,6 +25,45 @@ release" is exactly the contradiction
|
||||
|
||||
# Completed Steps
|
||||
|
||||
- 2026-08-09: Moved the logger to stderr and fixed `TTYHandler`'s
|
||||
discarded attributes
|
||||
([issue #82](https://git.eeqj.de/sneak/vaultik/issues/82),
|
||||
[issue #97](https://git.eeqj.de/sneak/vaultik/issues/97)). Two defects
|
||||
in `internal/log`, fixed together because both live in the handler
|
||||
construction path. The first: both handlers were built over
|
||||
`os.Stdout`, and `WARN`/`ERROR` are never suppressed, so a config file
|
||||
with group- or world-readable permissions was enough to put a log
|
||||
record inside a `--json` document and break `jq`. Diagnostics now go
|
||||
to stderr, and the TTY/JSON format choice follows stderr rather than
|
||||
stdout — testing the wrong stream would colorize records on a
|
||||
redirected stderr whenever stdout happened to be a terminal. This is
|
||||
user-visible: `--verbose` and `--debug` output moves to stderr too,
|
||||
which is documented in `README.md` under "stdout and stderr". It also
|
||||
let the local workaround in `internal/vaultik/snapshot_list.go` go:
|
||||
`warnWhileListing` had been hand-rolling structured-log formatting to
|
||||
reach a non-stdout writer, and the `jsonOutput` parameter threaded
|
||||
through the remote-listing helpers existed only to choose between the
|
||||
two writers. The collect-then-emit machinery around `listingWarning`
|
||||
stays, but on its remaining merit — warnings emitted in key order
|
||||
after `group.Wait()` are deterministic run to run, where emitting from
|
||||
the fetch workers would order them by network timing. The second
|
||||
defect: `TTYHandler.WithAttrs` and `WithGroup` discarded their
|
||||
arguments and returned the receiver while their doc comments claimed
|
||||
otherwise, so `log.With` attributes vanished on a terminal and
|
||||
appeared correctly in CI — failing precisely when someone is debugging
|
||||
interactively. Both now return a new handler (the receiver is never
|
||||
written to, since `slog` permits concurrent derivation), attributes
|
||||
persist across records, and grouping is implemented as dotted key
|
||||
prefixes, which is the only honest rendering for a format with nowhere
|
||||
to nest. New tests cover both, including one that feeds the same
|
||||
derivation chain to the TTY and JSON handlers and compares the
|
||||
attribute sets, so the two paths cannot drift apart again. Found and
|
||||
filed while verifying: the startup banner is written to stdout and
|
||||
`--json` does not suppress it
|
||||
([issue #106](https://git.eeqj.de/sneak/vaultik/issues/106)), which is
|
||||
a separate writer on a separate path and the remaining source of
|
||||
stdout contamination.
|
||||
|
||||
- 2026-08-09: Made the tagged-release path actually work on Gitea
|
||||
([issue #65](https://git.eeqj.de/sneak/vaultik/issues/65)). Three
|
||||
independent blockers, one of which was the whole
|
||||
|
||||
Reference in New Issue
Block a user