caddy-log-exporter/vendor/github.com/phsym/console-slog/handler.go
2024-09-19 11:21:05 +02:00

138 lines
3.0 KiB
Go

package console
import (
"context"
"io"
"log/slog"
"os"
"strings"
"sync"
"time"
)
var bufferPool = &sync.Pool{
New: func() any { return new(buffer) },
}
var cwd, _ = os.Getwd()
// HandlerOptions are options for a ConsoleHandler.
// A zero HandlerOptions consists entirely of default values.
type HandlerOptions struct {
// AddSource causes the handler to compute the source code position
// of the log statement and add a SourceKey attribute to the output.
AddSource bool
// Level reports the minimum record level that will be logged.
// The handler discards records with lower levels.
// If Level is nil, the handler assumes LevelInfo.
// The handler calls Level.Level for each record processed;
// to adjust the minimum level dynamically, use a LevelVar.
Level slog.Leveler
// Disable colorized output
NoColor bool
// TimeFormat is the format used for time.DateTime
TimeFormat string
// Theme defines the colorized output using ANSI escape sequences
Theme Theme
}
type Handler struct {
opts HandlerOptions
out io.Writer
group string
context buffer
enc *encoder
}
var _ slog.Handler = (*Handler)(nil)
// NewHandler creates a Handler that writes to w,
// using the given options.
// If opts is nil, the default options are used.
func NewHandler(out io.Writer, opts *HandlerOptions) *Handler {
if opts == nil {
opts = new(HandlerOptions)
}
if opts.Level == nil {
opts.Level = slog.LevelInfo
}
if opts.TimeFormat == "" {
opts.TimeFormat = time.DateTime
}
if opts.Theme == nil {
opts.Theme = NewDefaultTheme()
}
return &Handler{
opts: *opts, // Copy struct
out: out,
group: "",
context: nil,
enc: &encoder{opts: *opts},
}
}
// Enabled implements slog.Handler.
func (h *Handler) Enabled(_ context.Context, l slog.Level) bool {
return l >= h.opts.Level.Level()
}
// Handle implements slog.Handler.
func (h *Handler) Handle(_ context.Context, rec slog.Record) error {
buf := bufferPool.Get().(*buffer)
h.enc.writeTimestamp(buf, rec.Time)
h.enc.writeLevel(buf, rec.Level)
if h.opts.AddSource && rec.PC > 0 {
h.enc.writeSource(buf, rec.PC, cwd)
}
h.enc.writeMessage(buf, rec.Level, rec.Message)
buf.copy(&h.context)
rec.Attrs(func(a slog.Attr) bool {
h.enc.writeAttr(buf, a, h.group)
return true
})
h.enc.NewLine(buf)
if _, err := buf.WriteTo(h.out); err != nil {
buf.Reset()
bufferPool.Put(buf)
return err
}
bufferPool.Put(buf)
return nil
}
// WithAttrs implements slog.Handler.
func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler {
newCtx := h.context
for _, a := range attrs {
h.enc.writeAttr(&newCtx, a, h.group)
}
newCtx.Clip()
return &Handler{
opts: h.opts,
out: h.out,
group: h.group,
context: newCtx,
enc: h.enc,
}
}
// WithGroup implements slog.Handler.
func (h *Handler) WithGroup(name string) slog.Handler {
name = strings.TrimSpace(name)
if h.group != "" {
name = h.group + "." + name
}
return &Handler{
opts: h.opts,
out: h.out,
group: name,
context: h.context,
enc: h.enc,
}
}