# ADR-003: Exported Logger Interface **Status:** Accepted **Date:** 2026-03-18 ## Context Global ADR-001 establishes that app-facing modules define a local `Logger` interface satisfied by `logz.Logger` so that libraries do not import `logz` directly. For this duck-typing pattern to work, `logz` must export its `Logger` interface with a stable method set that other packages can replicate locally. If `Logger` were unexported, or if `New` returned `*slogLogger` (the concrete type), consumers would need to import `logz` just to name the type in a parameter or field declaration, coupling every module to the logging library. ## Decision `Logger` is an exported interface in the `logz` package: ```go type Logger interface { Debug(msg string, args ...any) Info(msg string, args ...any) Warn(msg string, args ...any) Error(msg string, err error, args ...any) With(args ...any) Logger WithContext(ctx context.Context) Logger } ``` `New(opts Options) Logger` returns the interface, not `*slogLogger`. The concrete type is unexported. `With` returns `Logger` (interface), not `*slogLogger` — this is enforced by the return type in the interface definition and by the compliance test. Modules that accept a logger define a local interface with the subset of methods they use (typically `Info`, `Warn`, `Error`). `logz.Logger` satisfies any such local interface because it is a superset. The `Error` signature deliberately differs from `slog`'s: `Error(msg string, err error, args ...any)`. The error is a first-class parameter rather than a key-value attribute, enabling automatic enrichment from duck-typed interfaces (`ErrorCode`, `ErrorContext`) without any extra caller code. ## Consequences - Tier 1+ modules can accept a logger via a local `Logger` interface without importing `logz`. They are decoupled from the logging backend. - `launcher`, which imports `logz` directly (it is the bootstrap layer), uses `logz.Logger` as the concrete type in its `New` signature. - Adding methods to `logz.Logger` is a breaking change for all callers that replicate the interface locally. Any new method must be evaluated carefully and accompanied by a version bump. - The `Error(msg, err, args...)` convention is not interchangeable with `slog`'s `Error(msg, args...)`. Adapters must account for this signature difference.