mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 19:13:34 +00:00
75 lines
1.9 KiB
Go
75 lines
1.9 KiB
Go
package log
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"log/slog"
|
|
"sync"
|
|
)
|
|
|
|
// SlogTextHandler extends the standard [slog.TextHandler] to provide custom formatting that is very similar
|
|
// to the default slog handler. It prefixes each log entry with a right-padded level indicator and message,
|
|
// while excluding the default time, level, and message attributes from the structured output.
|
|
//
|
|
// The output format is:
|
|
// LEVEL MESSAGE key1=value1 key2=value2
|
|
type SlogTextHandler struct {
|
|
*slog.TextHandler
|
|
opts slog.HandlerOptions
|
|
mu sync.Mutex
|
|
w io.Writer
|
|
}
|
|
|
|
func NewSlogTextHandler(w io.Writer, opts *slog.HandlerOptions) *SlogTextHandler {
|
|
if opts == nil {
|
|
opts = &slog.HandlerOptions{}
|
|
}
|
|
// Remove time, level, and message from the default attributes.
|
|
opts.ReplaceAttr = func(groups []string, a slog.Attr) slog.Attr {
|
|
if a.Key == slog.TimeKey || a.Key == slog.LevelKey || a.Key == slog.MessageKey {
|
|
return slog.Attr{}
|
|
}
|
|
return a
|
|
}
|
|
|
|
return &SlogTextHandler{
|
|
TextHandler: slog.NewTextHandler(w, opts),
|
|
opts: *opts,
|
|
w: w,
|
|
}
|
|
}
|
|
|
|
func (h *SlogTextHandler) Enabled(ctx context.Context, level slog.Level) bool {
|
|
return h.TextHandler.Enabled(ctx, level)
|
|
}
|
|
|
|
func (h *SlogTextHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
|
return h.TextHandler.WithAttrs(attrs)
|
|
}
|
|
|
|
func (h *SlogTextHandler) WithGroup(name string) slog.Handler {
|
|
return h.TextHandler.WithGroup(name)
|
|
}
|
|
|
|
func (h *SlogTextHandler) Handle(ctx context.Context, r slog.Record) error {
|
|
// Only log entries that are at or above the minimum level (INFO by default).
|
|
minLevel := slog.LevelInfo
|
|
if h.opts.Level != nil {
|
|
minLevel = h.opts.Level.Level()
|
|
}
|
|
if r.Level < minLevel {
|
|
return nil
|
|
}
|
|
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
|
|
levelMsg := fmt.Sprintf("%-5s %s ", r.Level.String(), r.Message)
|
|
if _, err := h.w.Write([]byte(levelMsg)); err != nil {
|
|
return err
|
|
}
|
|
|
|
return h.TextHandler.Handle(ctx, r)
|
|
}
|