-
Notifications
You must be signed in to change notification settings - Fork 2
/
handler_options.go
155 lines (137 loc) · 3.1 KB
/
handler_options.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package slogx
import (
"fmt"
"io"
"log/slog"
"os"
"strings"
)
func InitDefault() {
slog.SetDefault(slog.New(NewTracingHandler(NewHandler(&options{}))))
}
// New create a new *slog.Logger with tracing handler wrapper
func New(opts ...Option) *slog.Logger {
options := &options{
Options: Options{
DisableSource: false,
FullSource: false,
DisableTime: false,
},
Level: "info",
Format: "json",
Output: "stderr",
}
for _, o := range opts {
o(options)
}
h := NewHandler(options)
if options.Tracing {
h = NewTracingHandler(h)
}
return slog.New(h)
}
func NewHandler(options *options) slog.Handler {
var w io.Writer
if options.Writer != nil {
w = options.Writer
} else {
switch options.Output {
case "stdout":
w = os.Stdout
case "stderr", "":
w = os.Stderr
case "discard":
w = io.Discard
default:
var err error
w, err = os.OpenFile(options.Output, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644)
if err != nil {
slog.Error("failed to open log file, fallback to stderr", err)
w = os.Stderr
}
}
}
var theLevel slog.Level
switch options.Level {
case "debug":
theLevel = slog.LevelDebug
case "info":
theLevel = slog.LevelInfo
case "warn":
theLevel = slog.LevelWarn
case "error":
theLevel = slog.LevelError
default:
theLevel = slog.LevelInfo
}
lvl := &slog.LevelVar{}
lvl.Set(theLevel)
opts := NewHandlerOptions(lvl, &options.Options)
var th slog.Handler
switch options.Format {
case "text":
th = slog.NewTextHandler(w, &opts)
case "cli":
th = NewCliHandler(w, &CliHandlerOptions{DisableColor: options.DisableColor, HandlerOptions: opts})
case "json":
fallthrough
default:
th = slog.NewJSONHandler(w, &opts)
}
return th
}
func NewHandlerOptions(level slog.Leveler, opt *Options) slog.HandlerOptions {
ho := slog.HandlerOptions{
AddSource: !opt.DisableSource,
Level: level,
}
if !opt.DisableTime && (opt.FullSource || opt.DisableSource) {
return ho
}
ho.ReplaceAttr = func(groups []string, a slog.Attr) slog.Attr {
if opt.DisableTime {
if a.Key == slog.TimeKey {
// Remove time from the output.
return slog.Attr{}
}
}
switch a.Key {
case slog.SourceKey:
// handle short source file location
if !opt.DisableSource && !opt.FullSource {
return handleSourceKey(a)
}
}
return a
}
return ho
}
func handleSourceKey(a slog.Attr) slog.Attr {
file := a.Value.String()
if src, ok := a.Value.Any().(*slog.Source); ok {
// File is the absolute path to the file
short := src.File
// using short file like stdlog
// for i := len(file) - 1; i > 0; i-- {
// if file[i] == '/' {
// short = file[i+1:]
// break
// }
// }
// zap like short file
// https://github.com/uber-go/zap/blob/a55bdc32f526699c3b4cc51a2cc97e944d02fbbf/zapcore/entry.go#L102-L136
idx := strings.LastIndexByte(src.File, '/')
if idx > 0 {
// Find the penultimate separator.
idx = strings.LastIndexByte(src.File[:idx], '/')
if idx > 0 {
short = src.File[idx+1:]
}
}
file = fmt.Sprintf("%s:%d", short, src.Line)
}
return slog.Attr{
Key: a.Key,
Value: slog.StringValue(file),
}
}