refactor: framework modules log through diary components
- Each module logs through diary.For(<package>): cabana, lagoon, attach, cooler, postcard, beachcomber, lighthouse, centrifugo, flare, phrasebook, wristband, bouncer - App-published *slog.Logger overrides stay first; messages and attributes unchanged - sunscreen: InstallDefault documented as the compatibility entry point; diary wraps every channel - READMEs list diary as a dependency; logging docs: plugins use diary.For
This commit is contained in:
@@ -8,11 +8,11 @@ Credential-redacting slog handler that keeps API keys, tokens and passwords out
|
||||
|
||||
## Overview
|
||||
|
||||
`sunscreen` wraps any `log/slog` handler and rewrites every record before it is written: values of sensitive attribute keys become `[REDACTED]`, and credential shapes inside messages and string values are scrubbed. It is the SummerCMS counterpart of a Monolog tap that a WinterCMS application wires into its log channels to scrub contexts and messages. Every application `main` that `summer build` generates calls `sunscreen.InstallDefault(os.Stderr)` as its first statement, so the default logger, the standard `log` package and every plugin that falls back to `slog.Default` log through it from the start.
|
||||
`sunscreen` wraps any `log/slog` handler and rewrites every record before it is written: values of sensitive attribute keys become `[REDACTED]`, and credential shapes inside messages and string values are scrubbed. It is the SummerCMS counterpart of a Monolog tap that a WinterCMS application wires into its log channels to scrub contexts and messages. Every application `main` that `summer build` generates installs [diary](../diary/README.md), which wraps each of its log channels (console, stderr, daily files, null) with `sunscreen.Wrap`, so component loggers, the default logger and the standard `log` package all log through it from the start. `sunscreen.InstallDefault` stays as the compatibility entry point for programs that install their own default logger; there is no other install function.
|
||||
|
||||
## Role in the framework
|
||||
|
||||
A dependency-free leaf the application wires into its logger at startup. It is separate because it wraps the standard slog handler and applies to all log output, whichever module writes it.
|
||||
A dependency-free leaf that diary wraps around every log channel. It is separate because it wraps the standard slog handler and applies to all log output, whichever module writes it.
|
||||
|
||||
Use cases:
|
||||
|
||||
@@ -30,12 +30,11 @@ Use cases:
|
||||
|
||||
## Usage
|
||||
|
||||
The generated `main` already installs it:
|
||||
A program that does not use diary installs it as the default logger:
|
||||
|
||||
```go
|
||||
func run(args []string, out io.Writer) error {
|
||||
func main() {
|
||||
sunscreen.InstallDefault(os.Stderr)
|
||||
cfg, err := compass.Load("config")
|
||||
// ...
|
||||
}
|
||||
```
|
||||
@@ -55,7 +54,7 @@ Redaction is a safety net, not a licence: log ids and outcomes, never request bo
|
||||
| Identifier | Description |
|
||||
|------------|-------------|
|
||||
| `sunscreen.Wrap` | Returns a `slog.Handler` that redacts every record and every `WithAttrs` attribute before the wrapped handler sees it. Wrapping a sunscreen handler again returns it unchanged. |
|
||||
| `sunscreen.InstallDefault` | Makes a redacting text handler writing to the given writer the process default logger. |
|
||||
| `sunscreen.InstallDefault` | Makes a redacting text handler writing to the given writer the process default logger; the compatibility entry point for programs that do not install diary. |
|
||||
| `sunscreen.Scrub` | Replaces the Bearer, `sk-` and `x-api-key:` credential shapes in a string. |
|
||||
| `sunscreen.Redacted` | The replacement text, `[REDACTED]`. |
|
||||
| `sunscreen.RedactedKeys` | Returns a copy of the attribute keys whose values are always redacted. |
|
||||
|
||||
@@ -87,10 +87,15 @@ func Wrap(next slog.Handler) slog.Handler {
|
||||
}
|
||||
|
||||
// InstallDefault makes a redacting text handler writing to w the process
|
||||
// default logger (slog.SetDefault), so plugins that fall back to
|
||||
// slog.Default and the standard log package both log through it. It builds
|
||||
// a fresh slog.TextHandler instead of wrapping the existing default, whose
|
||||
// output goes through the log package that SetDefault redirects back here.
|
||||
// default logger (slog.SetDefault), so code that logs through slog.Default
|
||||
// and the standard log package both log through it. It builds a fresh
|
||||
// slog.TextHandler instead of wrapping the existing default, whose output
|
||||
// goes through the log package that SetDefault redirects back here.
|
||||
//
|
||||
// Generated applications no longer call it: they install the diary module,
|
||||
// which wraps every log channel with Wrap. InstallDefault stays as the
|
||||
// compatibility entry point for programs that install their own default
|
||||
// logger.
|
||||
func InstallDefault(w io.Writer) {
|
||||
slog.SetDefault(slog.New(Wrap(slog.NewTextHandler(w, nil))))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user