Config.Logger is a *slog.Logger. The nexus.Logger interface and NoopLogger are gone.
Logger discards everything.
Printing a client or a config
Both are safe to print and to log.Config and *Client implement fmt.Stringer,
fmt.GoStringer and slog.LogValuer, so every formatting channel renders the same
redacted form:
fmt’s own rules send %#v to
GoStringer rather than to Stringer, and a slog handler resolves LogValuer before
it formats a value at all. APIKey:set is the whole answer about the credential - not a
prefix, not a length. The counts and the base URL are there deliberately: a redacted
form nobody can read gets replaced by a raw one.
Two things this cannot cover. fmt reaches a value in an unexported field of
another struct by reflection and cannot call a method on it, so %+v on your own type
holding a nexus.Config in an unexported field renders that config field by field -
keep the field exported, or give your type its own String(). And the value GetSecret
returns is a plain string: what it goes into afterwards is yours.
Why *slog.Logger
log/slog is the standard library’s structured logger and the ecosystem has settled on
its Handler interface, so accepting a *slog.Logger reaches every backend without the
SDK depending on any of them. zap, zerolog and logrus all provide a handler, and so does
anything else worth using.
It also makes the output aggregatable. Values arrive as attributes rather than baked
into the message text, so every occurrence of an event shares one message template:
“how often did the stream drop” becomes a countable query rather than a substring search
over lines that are each slightly different.
What the output looks like
component attribute naming the subsystem:
So the three can be routed or filtered independently without parsing message text.
Levels
Nothing above
Error is ever emitted: the SDK does not decide that an application
should stop.
Scoping the SDK’s output
Pass a logger that already carries attributes of your own and everything the SDK emits inherits them:Secrets never appear
Secret values are never logged, as a message or as an attribute, and neither are secret key names. The same holds for the API key, the workload OIDC token and the session JWT. A test drives a sync carrying both a text and a file-type secret through a capturing handler at debug level and fails if any of them shows up in the output, so this is a checked property rather than a convention.Observer faults
AStreamObserver callback that panics is recovered, and the fault is
reported here at Error with the hook name and a stack trace:
