cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.65.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/log/handler.go

142lines · modecode

1package log
2
3import (
4 "bytes"
5 "context"
6 "encoding/json"
7 "fmt"
8 "io"
9 "log/slog"
10 "strings"
11 "sync"
12)
13
14const (
15 dim = 2
16 fgHiRed = 91
17 fgHiYellow = 93
18 fgHiBlue = 94
19 fgHiMagenta = 95
20 fgHiCyan = 96
21 fgHiWhite = 97
22)
23
24type handler struct {
25 dst io.Writer
26
27 escaper *strings.Replacer
28 level slog.Level
29 mtx sync.Mutex
30 noColor bool
31}
32
33func newHandler(dst io.Writer, level slog.Level, noColor bool) *handler {
34 h := handler{
35 mtx: sync.Mutex{},
36 dst: dst,
37 level: level,
38 noColor: noColor,
39 escaper: strings.NewReplacer(`"`, `\"`),
40 }
41 return &h
42}
43
44func (h *handler) Enabled(_ context.Context, level slog.Level) bool {
45 return level >= h.level
46}
47
48func (h *handler) Handle(_ context.Context, record slog.Record) error {
49 buf := bytes.NewBuffer(make([]byte, 0, 128))
50
51 var lc int
52 switch record.Level {
53 case slog.LevelInfo:
54 lc = fgHiWhite
55 case slog.LevelError:
56 lc = fgHiRed
57 case slog.LevelWarn:
58 lc = fgHiYellow
59 case slog.LevelDebug:
60 lc = fgHiMagenta
61 }
62 h.printKey(buf, "level")
63 h.printVal(buf, record.Level.String(), lc)
64 _, _ = buf.WriteRune(' ')
65 h.printKey(buf, "msg")
66 h.printVal(buf, record.Message, fgHiWhite)
67
68 record.Attrs(func(attr slog.Attr) bool {
69 _, _ = buf.WriteRune(' ')
70 h.appendAttr(buf, attr)
71 return true
72 })
73 _, _ = buf.WriteRune('\n')
74
75 h.mtx.Lock()
76 defer h.mtx.Unlock()
77
78 if _, err := buf.WriteTo(h.dst); err != nil {
79 return fmt.Errorf("failed to write buffer: %w", err)
80 }
81
82 return nil
83}
84
85func (h *handler) WithAttrs(_ []slog.Attr) slog.Handler {
86 return h
87}
88
89func (h *handler) WithGroup(_ string) slog.Handler {
90 return h
91}
92
93func (h *handler) printKey(buf *bytes.Buffer, s string) {
94 _, _ = buf.WriteString(h.maybeWriteColor(s+"=", dim))
95}
96
97func (h *handler) printVal(buf *bytes.Buffer, s string, color int) {
98 if !strings.HasPrefix(s, "[") && !strings.HasPrefix(s, "{") && strings.Contains(s, " ") {
99 s = "\"" + h.escaper.Replace(s) + "\""
100 }
101 _, _ = buf.WriteString(h.maybeWriteColor(s, color))
102}
103
104func (h *handler) maybeWriteColor(s string, color int) string {
105 if h.noColor {
106 return s
107 }
108 return fmt.Sprintf("\033[%dm%s\033[0m", color, s)
109}
110
111func (h *handler) appendAttr(buf *bytes.Buffer, attr slog.Attr) {
112 attr.Value = attr.Value.Resolve()
113
114 h.printKey(buf, attr.Key)
115
116 // nolint: exhaustive
117 switch attr.Value.Kind() {
118 case slog.KindAny:
119 switch attr.Value.Any().(type) {
120 case error:
121 h.printVal(buf, formatString(attr), fgHiRed)
122 default:
123 h.printVal(buf, formatAny(attr), fgHiCyan)
124 }
125 case slog.KindString:
126 h.printVal(buf, formatString(attr), fgHiCyan)
127 default:
128 h.printVal(buf, formatAny(attr), fgHiBlue)
129 }
130}
131
132func formatAny(attr slog.Attr) string {
133 data, err := json.Marshal(attr.Value.Any())
134 if err != nil {
135 return attr.Value.String()
136 }
137 return string(data)
138}
139
140func formatString(attr slog.Attr) string {
141 return strings.ReplaceAll(attr.Value.String(), "\n", "\\n")
142}
143