mirror of https://github.com/databricks/cli.git
103 lines
2.5 KiB
Go
103 lines
2.5 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"log/slog"
|
|
"sync"
|
|
|
|
"github.com/databricks/cli/libs/log"
|
|
)
|
|
|
|
// friendlyHandler implements a custom [slog.Handler] that writes
|
|
// human readable (and colorized) log lines to a terminal.
|
|
//
|
|
// The implementation is based on the guide at:
|
|
// https://github.com/golang/example/blob/master/slog-handler-guide/README.md
|
|
type friendlyHandler struct {
|
|
opts Options
|
|
mu *sync.Mutex
|
|
out io.Writer
|
|
|
|
// List of colors to use for formatting.
|
|
ttyColors
|
|
|
|
// Cache (colorized) level strings.
|
|
levelTrace string
|
|
levelDebug string
|
|
levelInfo string
|
|
levelWarn string
|
|
levelError string
|
|
}
|
|
|
|
func NewFriendlyHandler(out io.Writer, opts *Options) slog.Handler {
|
|
h := &friendlyHandler{out: out, mu: &sync.Mutex{}}
|
|
if opts != nil {
|
|
h.opts = *opts
|
|
}
|
|
if h.opts.Level == nil {
|
|
h.opts.Level = slog.LevelInfo
|
|
}
|
|
|
|
h.ttyColors = newColors(opts.Color)
|
|
|
|
// Cache (colorized) level strings.
|
|
// The colors to use for each level are configured in `colors.go`.
|
|
h.levelTrace = h.sprintf(ttyColorLevelTrace, "%s", "Trace: ")
|
|
h.levelDebug = h.sprintf(ttyColorLevelDebug, "%s", "Debug: ")
|
|
h.levelInfo = h.sprintf(ttyColorLevelInfo, "%s", "Info: ")
|
|
h.levelWarn = h.sprintf(ttyColorLevelWarn, "%s", "Warn: ")
|
|
h.levelError = h.sprintf(ttyColorLevelError, "%s", "Error: ")
|
|
return h
|
|
}
|
|
|
|
func (h *friendlyHandler) sprint(color ttyColor, args ...any) string {
|
|
return h.ttyColors[color].Sprint(args...)
|
|
}
|
|
|
|
func (h *friendlyHandler) sprintf(color ttyColor, format string, args ...any) string {
|
|
return h.ttyColors[color].Sprintf(format, args...)
|
|
}
|
|
|
|
func (h *friendlyHandler) coloredLevel(r slog.Record) string {
|
|
switch r.Level {
|
|
case log.LevelTrace:
|
|
return h.levelTrace
|
|
case log.LevelDebug:
|
|
return h.levelDebug
|
|
case log.LevelInfo:
|
|
return h.levelInfo
|
|
case log.LevelWarn:
|
|
return h.levelWarn
|
|
case log.LevelError:
|
|
return h.levelError
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// Enabled implements slog.Handler.
|
|
func (h *friendlyHandler) Enabled(ctx context.Context, level slog.Level) bool {
|
|
return level >= h.opts.Level.Level()
|
|
}
|
|
|
|
// Handle implements slog.Handler.
|
|
func (h *friendlyHandler) Handle(ctx context.Context, r slog.Record) error {
|
|
out := fmt.Sprintf("%s%s\n", h.coloredLevel(r), h.sprint(ttyColorMessage, r.Message))
|
|
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
_, err := h.out.Write([]byte(out))
|
|
return err
|
|
}
|
|
|
|
// WithGroup implements slog.Handler.
|
|
func (h *friendlyHandler) WithGroup(name string) slog.Handler {
|
|
return h
|
|
}
|
|
|
|
// WithAttrs implements slog.Handler.
|
|
func (h *friendlyHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
|
return h
|
|
}
|