-
Release v1.0.0 Stable
released this
2026-05-11 18:51:47 -06:00 | 1 commits to main since this releasev1.0.0
code.nochebuena.dev/go/logzOverview
logzv1.0.0 commits the structured logging API as stable. All v0.9.0 roadmap
items are resolved. The module ships a minimal six-methodLoggerinterface
backed by stdliblog/slog, with zero external dependencies, owned context keys
for request correlation, and a duck-typedxerrorsenrichment bridge validated
under concurrent production load.What Changed Since v0.9.0
New:
Options.Writer io.Writertype Options struct { Level slog.Level JSON bool StaticArgs []any Writer io.Writer // nil → os.Stdout }The output destination is now configurable. When
Writeris nil the behavior is
identical to v0.9.0 (writes toos.Stdout). Anyio.Writerimplementation is
accepted:// Test log capture var buf bytes.Buffer l := logz.New(logz.Options{Writer: &buf}) // File-based audit trail f, _ := os.OpenFile("audit.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) l := logz.New(logz.Options{Writer: f, JSON: true}) // Both stdout and file l := logz.New(logz.Options{Writer: io.MultiWriter(os.Stdout, f), JSON: true})Roadmap items resolved
Item Resolution io.Writerconfigurable✅ Options.Writer— nil defaults toos.StdoutLog sampling ❌ No — belongs in slog.Handlerwrappers or the observability layerConcurrent xerrors enrichment ✅ Validated — ErrorContext()is read-only post-constructionLoggerinterface is final✅ Committed — 6 methods; Fatal/Panicintentionally excludedWithFieldsmerge concurrency✅ Validated — context.WithValueimmutability guarantees safetyFull API (stable)
Logger— interface:Debug,Info,Warn,Error(msg, err, args...),
With(args...) Logger,WithContext(ctx) Logger.Options—Level slog.Level,JSON bool,StaticArgs []any,
Writer io.Writer(nil →os.Stdout). Zero value is valid.New(opts Options) Logger— constructor; returnsLogger, never the concrete type.WithRequestID(ctx, id) context.Context— stores a correlation ID under this
package's private context key.GetRequestID(ctx) string— retrieves the ID; returns""if absent or ctx nil.WithField(ctx, key, value) context.Context— adds a single field to the context.WithFields(ctx, fields) context.Context— merges multiple fields; does not
overwrite existing keys.Logger.WithContext(ctx) Logger— child logger pre-enriched withrequest_id
and any extra fields from the context; returns the same logger if ctx carries no
relevant values.Automatic error enrichment —
Logger.ErrorinspectserrforErrorCode()
andErrorContext()duck-type methods (satisfied by*xerrors.Err) and appends
error_codeand context fields automatically. No import betweenlogzand
xerrorsis required in either direction.Migration from v0.9.0
No breaking changes.
Options{}continues to write toos.Stdout.go get code.nochebuena.dev/go/logz@v1.0.0Downloads
-
Release v0.9.0 Stable
released this
2026-03-18 13:33:16 -06:00 | 2 commits to main since this releasev0.9.0
code.nochebuena.dev/go/logzOverview
logzprovides a stableLoggerinterface backed by the stdliblog/slogpackage, with no external logging library dependencies. It owns the request correlation ID context key and an extra-fields context key, supplying helpers to attach and retrieve them so any downstream handler can enrich log records from the context without manual field threading. When an error passed toLogger.Errorimplements theErrorCode()orErrorContext()duck-type interfaces, the structured fields are automatically appended to the log record — withoutlogzimportingxerrors.What's Included
Loggerinterface —Debug,Info,Warn,Error(msg, err, args...),With,WithContextOptionsstruct —Level slog.Level,JSON bool,StaticArgs []anyNew(opts Options) Logger— constructs aLoggerwriting toos.Stdout; zero value ofOptionsis valid (INFO level, text output)WithRequestID(ctx, id string) context.Context— stores a correlation ID in the context; owned by this packageGetRequestID(ctx context.Context) string— retrieves the correlation ID; returns""if absent or ctx is nilWithField(ctx, key string, value any) context.Context— adds a single key-value logging field to the contextWithFields(ctx context.Context, fields map[string]any) context.Context— merges multiple key-value fields into the context; does not overwrite existing fields- Automatic
error_codeand context-field enrichment inLogger.Errorvia duck-typederrorWithCode/errorWithContextprivate interfaces
Installation
require code.nochebuena.dev/go/logz v0.9.0Design Highlights
- Wraps
log/slogexclusively — no external logging library is required or vendored (seedocs/adr/ADR-001-slog-stdlib-backend.md). logzowns the context keysctxRequestIDKey{}andctxExtraFieldsKey{}as unexported struct types, preventing collisions with any other package's context keys (seedocs/adr/ADR-002-requestid-context-ownership.md).Newreturns theLoggerinterface, not the concrete*slogLogger, andWithalso returnsLogger— the concrete type is never exported, making the interface the only public surface and allowing safe local re-declaration in libraries (seedocs/adr/ADR-003-exported-logger-interface.md).Errortreatserras a first-class parameter (not a variadic arg), enabling the automatic duck-typed enrichment path;xerrors.Errsatisfies this without any import between the two packages.
Known Limitations & Edge Cases
- All log output is always written to
os.Stdout. There is no configurableio.Writer— routing to files, syslog, or other sinks must be handled by the process supervisor or a shell redirect. - There is no log sampling or rate limiting. A high-frequency error loop will produce one log record per call with no throttling.
WithFieldandWithFieldscreate a new map and a new context value on every call. In hot paths (e.g. per-request middleware), repeated calls accumulate allocations; batch them with a singleWithFieldscall where possible.WithContext(nil)is handled safely (returns the same logger), butWithRequestIDandWithFielddo not accept nil contexts and will panic.StaticArgsinOptionsare attached at logger construction time only; there is no way to inject static args into an existing logger without creating a new one viaWith.Logger.Withreturns aLoggerinterface — if the caller needsWithContextafterWith, that is supported, but the full method set ofslogLoggeris not accessible afterWith.
v0.9.0 → v1.0.0 Roadmap
- Evaluate whether a configurable
io.Writer(passed viaOptions) is required for production use cases such as test log capture or file-based audit trails. - Decide whether log sampling belongs in this package or should be left to
slog.Handlerwrappers, and document the recommended pattern. - Validate the duck-typed
xerrorsenrichment path under concurrent production load to confirm no race conditions on theErrorContext()map read path. - Confirm that the
Loggerinterface method set is final before 1.0; any addition is a breaking change for all callers that re-declare the interface locally. - Achieve production validation of the
WithFieldsmerge semantics under concurrent middleware chains.
v0.9.0 rationale: The API is stable and intentional — designed through multiple architecture reviews and tested end-to-end via the todo-api POC (SQLite, RBAC, middleware stack, HTTP handlers). The module is not yet battle-tested in production for all edge cases, and the pre-1.0 designation preserves the option for minor API refinements based on real-world use.
Downloads