mirror of
https://github.com/h44z/wg-portal.git
synced 2025-04-19 08:55:12 +00:00
169 lines
4.1 KiB
Go
169 lines
4.1 KiB
Go
package internal
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"log/slog"
|
|
"os"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// SetupLogging initializes the global logger with the given level and format
|
|
func SetupLogging(level string, pretty, json bool) {
|
|
var logLevel = new(slog.LevelVar)
|
|
|
|
switch strings.ToLower(level) {
|
|
case "trace", "debug":
|
|
logLevel.Set(slog.LevelDebug)
|
|
case "info", "information":
|
|
logLevel.Set(slog.LevelInfo)
|
|
case "warn", "warning":
|
|
logLevel.Set(slog.LevelWarn)
|
|
case "error":
|
|
logLevel.Set(slog.LevelError)
|
|
default:
|
|
logLevel.Set(slog.LevelInfo)
|
|
}
|
|
|
|
opts := &slog.HandlerOptions{
|
|
Level: logLevel,
|
|
}
|
|
|
|
// send everything to stderr as suggested in https://www.gnu.org/software/libc/manual/html_node/Standard-Streams.html
|
|
output := os.Stderr
|
|
|
|
var handler slog.Handler
|
|
switch {
|
|
case json:
|
|
handler = slog.NewJSONHandler(output, opts)
|
|
case pretty:
|
|
handler = NewPrettyHandler(output, opts)
|
|
default:
|
|
handler = slog.NewTextHandler(output, opts)
|
|
}
|
|
|
|
logger := slog.New(handler)
|
|
|
|
slog.SetDefault(logger)
|
|
}
|
|
|
|
// PrettyHandler is a slog.Handler that formats log records in a human-readable way.
|
|
// It mimics the behavior of the slog.Default() handler.
|
|
type PrettyHandler struct {
|
|
opts slog.HandlerOptions
|
|
prefix string // preformatted group names followed by a dot
|
|
preformat string // preformatted Attrs, with an initial space
|
|
timeFormat string
|
|
|
|
mu sync.Mutex
|
|
w io.Writer
|
|
}
|
|
|
|
// NewPrettyHandler creates a new PrettyHandler.
|
|
func NewPrettyHandler(w io.Writer, opts *slog.HandlerOptions) *PrettyHandler {
|
|
h := &PrettyHandler{w: w}
|
|
if opts != nil {
|
|
h.opts = *opts
|
|
}
|
|
if h.opts.ReplaceAttr == nil {
|
|
h.opts.ReplaceAttr = func(_ []string, a slog.Attr) slog.Attr { return a }
|
|
}
|
|
|
|
h.timeFormat = "2006/01/02 15:04:05"
|
|
|
|
return h
|
|
}
|
|
|
|
// Enabled reports whether the handler handles records at the given level.
|
|
func (h *PrettyHandler) Enabled(_ context.Context, level slog.Level) bool {
|
|
minLevel := slog.LevelInfo
|
|
if h.opts.Level != nil {
|
|
minLevel = h.opts.Level.Level()
|
|
}
|
|
return level >= minLevel
|
|
}
|
|
|
|
// WithGroup returns a new Handler with the given group appended to the handler's
|
|
func (h *PrettyHandler) WithGroup(name string) slog.Handler {
|
|
return &PrettyHandler{
|
|
w: h.w,
|
|
opts: h.opts,
|
|
preformat: h.preformat,
|
|
prefix: h.prefix + name + ".",
|
|
}
|
|
}
|
|
|
|
// WithAttrs returns a new Handler whose attributes consist of the handler's
|
|
func (h *PrettyHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
|
var buf []byte
|
|
for _, a := range attrs {
|
|
buf = h.appendAttr(buf, h.prefix, a)
|
|
}
|
|
return &PrettyHandler{
|
|
w: h.w,
|
|
opts: h.opts,
|
|
prefix: h.prefix,
|
|
preformat: h.preformat + string(buf),
|
|
}
|
|
}
|
|
|
|
// Handle formats its argument Record as a single line of text ending in a newline.
|
|
func (h *PrettyHandler) Handle(_ context.Context, r slog.Record) error {
|
|
var buf []byte
|
|
if !r.Time.IsZero() {
|
|
buf = r.Time.AppendFormat(buf, h.timeFormat)
|
|
buf = append(buf, ' ')
|
|
}
|
|
|
|
// Make sure that each level has the same length.
|
|
// The shortest level is "INFO", thus we add a space to the end of the level string
|
|
levText := (r.Level.String() + " ")[0:5]
|
|
|
|
buf = append(buf, levText...)
|
|
buf = append(buf, ' ')
|
|
if h.opts.AddSource && r.PC != 0 {
|
|
fs := runtime.CallersFrames([]uintptr{r.PC})
|
|
f, _ := fs.Next()
|
|
buf = append(buf, f.File...)
|
|
buf = append(buf, ':')
|
|
buf = strconv.AppendInt(buf, int64(f.Line), 10)
|
|
buf = append(buf, ' ')
|
|
}
|
|
buf = append(buf, r.Message...)
|
|
buf = append(buf, h.preformat...)
|
|
r.Attrs(func(a slog.Attr) bool {
|
|
buf = h.appendAttr(buf, h.prefix, a)
|
|
return true
|
|
})
|
|
buf = append(buf, '\n')
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
_, err := h.w.Write(buf)
|
|
return err
|
|
}
|
|
|
|
func (h *PrettyHandler) appendAttr(buf []byte, prefix string, a slog.Attr) []byte {
|
|
if a.Equal(slog.Attr{}) {
|
|
return buf
|
|
}
|
|
if a.Value.Kind() != slog.KindGroup {
|
|
buf = append(buf, ' ')
|
|
buf = append(buf, prefix...)
|
|
buf = append(buf, a.Key...)
|
|
buf = append(buf, '=')
|
|
return fmt.Appendf(buf, "%v", a.Value.Any())
|
|
}
|
|
// Group
|
|
if a.Key != "" {
|
|
prefix += a.Key + "."
|
|
}
|
|
for _, a := range a.Value.Group() {
|
|
buf = h.appendAttr(buf, prefix, a)
|
|
}
|
|
return buf
|
|
}
|