mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-08 00:22:14 +01:00
138 lines
3.6 KiB
Go
138 lines
3.6 KiB
Go
package log
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"os"
|
|
"strings"
|
|
|
|
"go.opentelemetry.io/otel/trace"
|
|
"golang.org/x/term"
|
|
)
|
|
|
|
const (
|
|
autoLoggingFormat = "auto"
|
|
jsonLoggingFormat = "json"
|
|
textLoggingFormat = "text"
|
|
)
|
|
|
|
// traceContextHandler is an internal wrapper that specifically injects
|
|
// trace_id and span_id into the log record before they are written to the standard output.
|
|
type traceContextHandler struct {
|
|
slog.Handler
|
|
}
|
|
|
|
func (h traceContextHandler) Handle(ctx context.Context, r slog.Record) error {
|
|
if spanCtx := trace.SpanContextFromContext(ctx); spanCtx.IsValid() {
|
|
// Since slog.Record is immutable with regards to adding attributes in-place,
|
|
// we must clone and add them.
|
|
newR := slog.NewRecord(r.Time, r.Level, r.Message, r.PC)
|
|
r.Attrs(func(a slog.Attr) bool {
|
|
newR.AddAttrs(a)
|
|
return true
|
|
})
|
|
newR.AddAttrs(
|
|
slog.String("trace_id", spanCtx.TraceID().String()),
|
|
slog.String("span_id", spanCtx.SpanID().String()),
|
|
)
|
|
r = newR
|
|
}
|
|
|
|
return h.Handler.Handle(ctx, r)
|
|
}
|
|
|
|
func (h traceContextHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
|
return traceContextHandler{Handler: h.Handler.WithAttrs(attrs)}
|
|
}
|
|
|
|
func (h traceContextHandler) WithGroup(name string) slog.Handler {
|
|
return traceContextHandler{Handler: h.Handler.WithGroup(name)}
|
|
}
|
|
|
|
// NewStdHandler returns a [slog.Handler] instance for the standard output.
|
|
// upperLevelCase is the value of the level-case setting that keeps the level
|
|
// field uppercase in the standard output. It mirrors gotenberg.UpperLevelCase,
|
|
// duplicated here because the internal log package cannot import gotenberg.
|
|
const upperLevelCase = "upper"
|
|
|
|
func NewStdHandler(level slog.Level, format string, fieldsPrefix string, enableGcpFields bool, levelCase string) (slog.Handler, error) {
|
|
// #nosec: G115
|
|
isTerminal := term.IsTerminal(int(os.Stdout.Fd()))
|
|
|
|
// Normalize the log format based on the output device.
|
|
if format == autoLoggingFormat {
|
|
if isTerminal {
|
|
format = textLoggingFormat
|
|
} else {
|
|
format = jsonLoggingFormat
|
|
}
|
|
}
|
|
|
|
opts := &slog.HandlerOptions{
|
|
Level: level,
|
|
}
|
|
|
|
opts.ReplaceAttr = func(groups []string, a slog.Attr) slog.Attr {
|
|
// Configure level encoding based on format and GCP settings.
|
|
if a.Key == slog.LevelKey {
|
|
l := a.Value.Any().(slog.Level)
|
|
switch {
|
|
case format == textLoggingFormat && isTerminal:
|
|
if enableGcpFields {
|
|
a.Value = slog.StringValue(gcpSeverityColorEncoder(l))
|
|
} else {
|
|
a.Value = slog.StringValue(levelToColor(l).Add(l.String()))
|
|
}
|
|
case enableGcpFields && format != textLoggingFormat:
|
|
a.Key = "severity"
|
|
a.Value = slog.StringValue(gcpSeverity(l))
|
|
default:
|
|
if levelCase == upperLevelCase {
|
|
a.Value = slog.StringValue(l.String())
|
|
} else {
|
|
a.Value = slog.StringValue(strings.ToLower(l.String()))
|
|
}
|
|
}
|
|
}
|
|
|
|
if a.Key == slog.TimeKey {
|
|
if enableGcpFields && format != textLoggingFormat {
|
|
a.Key = "time"
|
|
} else {
|
|
a.Key = "ts"
|
|
}
|
|
|
|
if isTerminal {
|
|
a.Value = slog.StringValue(a.Value.Time().Local().Format("2006/01/02 15:04:05.000"))
|
|
} else if !enableGcpFields {
|
|
a.Value = slog.Float64Value(float64(a.Value.Time().UnixNano()) / 1e9)
|
|
}
|
|
}
|
|
|
|
if a.Key == slog.MessageKey {
|
|
if enableGcpFields && format != textLoggingFormat {
|
|
a.Key = "message"
|
|
} else {
|
|
a.Key = "msg"
|
|
}
|
|
}
|
|
|
|
return a
|
|
}
|
|
|
|
var handler slog.Handler
|
|
if format == textLoggingFormat {
|
|
handler = slog.NewTextHandler(os.Stderr, opts)
|
|
} else {
|
|
handler = slog.NewJSONHandler(os.Stderr, opts)
|
|
}
|
|
|
|
return traceContextHandler{Handler: handler}, nil
|
|
}
|
|
|
|
func gcpSeverityColorEncoder(l slog.Level) string {
|
|
severity := gcpSeverity(l)
|
|
c := levelToColor(l)
|
|
return c.Add(severity)
|
|
}
|