Add structured logging infrastructure (#246)
New global flags:
* `--log-file FILE`: can be literal `stdout`, `stderr`, or a file name (default `stderr`)
* `--log-level LEVEL`: can be `error`, `warn`, `info`, `debug`, `trace`, or `disabled` (default `disabled`)
* `--log-format TYPE`: can be `text` or `json` (default `text`)
New functions in the `log` package take a `context.Context` and retrieve
the logger from said context.
Because we carry the logger in a context, adding
[attributes](https://pkg.go.dev/golang.org/x/exp/slog#hdr-Attrs_and_Values)
to the logger can be done as follows:
```go
ctx = log.NewContext(ctx, log.GetLogger(ctx).With("foo", "bar"))
```
2023-03-16 13:46:53 +00:00
|
|
|
package log
|
|
|
|
|
2023-08-15 13:50:40 +00:00
|
|
|
import "log/slog"
|
Add structured logging infrastructure (#246)
New global flags:
* `--log-file FILE`: can be literal `stdout`, `stderr`, or a file name (default `stderr`)
* `--log-level LEVEL`: can be `error`, `warn`, `info`, `debug`, `trace`, or `disabled` (default `disabled`)
* `--log-format TYPE`: can be `text` or `json` (default `text`)
New functions in the `log` package take a `context.Context` and retrieve
the logger from said context.
Because we carry the logger in a context, adding
[attributes](https://pkg.go.dev/golang.org/x/exp/slog#hdr-Attrs_and_Values)
to the logger can be done as follows:
```go
ctx = log.NewContext(ctx, log.GetLogger(ctx).With("foo", "bar"))
```
2023-03-16 13:46:53 +00:00
|
|
|
|
|
|
|
const (
|
|
|
|
LevelTrace slog.Level = -8
|
|
|
|
LevelDebug slog.Level = -4
|
|
|
|
LevelInfo slog.Level = 0
|
|
|
|
LevelWarn slog.Level = 4
|
|
|
|
LevelError slog.Level = 8
|
|
|
|
|
|
|
|
// LevelDisabled means nothing is ever logged (no call site may use this level).
|
|
|
|
LevelDisabled slog.Level = 16
|
|
|
|
)
|
|
|
|
|
|
|
|
// ReplaceLevelAttr rewrites the level attribute to the correct string value.
|
|
|
|
// This is done because slog doesn't include trace level logging and
|
|
|
|
// otherwise trace logs show up as `DEBUG-4`.
|
|
|
|
func ReplaceLevelAttr(groups []string, a slog.Attr) slog.Attr {
|
|
|
|
if a.Key != slog.LevelKey {
|
|
|
|
return a
|
|
|
|
}
|
|
|
|
|
|
|
|
level := a.Value.Any().(slog.Level)
|
|
|
|
switch {
|
|
|
|
case level < LevelDebug:
|
|
|
|
a.Value = slog.StringValue("TRACE")
|
|
|
|
case level < LevelInfo:
|
|
|
|
a.Value = slog.StringValue("DEBUG")
|
|
|
|
case level < LevelWarn:
|
|
|
|
a.Value = slog.StringValue("INFO")
|
|
|
|
case level < LevelError:
|
|
|
|
a.Value = slog.StringValue("WARNING")
|
|
|
|
default:
|
|
|
|
a.Value = slog.StringValue("ERROR")
|
|
|
|
}
|
|
|
|
|
|
|
|
return a
|
|
|
|
}
|