-
Notifications
You must be signed in to change notification settings - Fork 0
/
setup.go
217 lines (208 loc) · 6.91 KB
/
setup.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
//
// slogf sets up a logger based on Go's slog package at 1.21.
//
// Idea is to switch to a structural logging that gives key and value at the same time.
//
// Specs:
//
// - Support 2 log levels, debug and info. Setting debug = true for debug level while false means
// info level.
// Debug level displays DEBUG, INFO, WARN, ERROR, FATAL logs.
// Info level displays INFO, WARN, ERROR, FATAL logs.
//
// - Support 2 log formats, Text and JSON.
// E.g. Text
// time=2023-07-11T17:12:46.649Z level=INFO source=main.go:29 msg="Entered main."
// E.g. JSON
// {"time":"2023-07-11T17:05:15.924382Z","level":"INFO","source":{"function":"main.main","file":"main.go","line":29},"msg":"Entered main."}
//
// - Support 2 log styles
// 1. Extra key value pairs
// Debug(), Info(), Warn(), Error(), Fatal() supports extra arguments and attributes.
// Way to call:
// Debug(message, key1, value1, key2, value2) while message is string type value.
// For passing err directly, just append .Error() after err first!
// E.g. Debug("Hello world!", "Hello", "Peter Parker")
// =>
// {"time":"2023-07-11T17:05:15.924556Z","level":"DEBUG","source":{"function":"main.main","file":"main.go","line":32},"msg":"Hello world!", "Hello":"Peter Parker"}
// 2. Print format one liner
// Debugf(), Infof(), Warnf(), Errorf(), Fatalf() supports print format style.
// Way to call:
// Debugf(format, substitue)
// E.g. Debugf("Hello, %v!", "Peter Parker")
// =>
// {"time":"2023-07-11T17:05:15.924556Z","level":"DEBUG","source":{"function":"main.main","file":"main.go","line":32},"msg":"Hello, Peter Parker!"}
//
//
package slogf
import (
"strings"
"context"
"fmt"
"os"
"path/filepath"
"runtime"
"time"
"log/slog"
)
var (
Logger *slog.Logger
)
const (
LevelFatal = slog.Level(12)
)
//
// Actual logging in different levels.
//
// Debug() wraps around slog.Debug()
func Debug(format string, args ...any) {
if !Logger.Enabled(context.Background(), slog.LevelDebug) {
return
}
var pcs [1]uintptr
runtime.Callers(2, pcs[:]) // skip [Callers, Infof]
r := slog.NewRecord(time.Now(), slog.LevelDebug, format, pcs[0])
r.Add(args...)
_ = Logger.Handler().Handle(context.Background(), r)
}
//
// Debugf() provides flexibility to log with the 'printf' style
func Debugf(format string, args ...any) {
if !Logger.Enabled(context.Background(), slog.LevelDebug) {
return
}
var pcs [1]uintptr
runtime.Callers(2, pcs[:]) // skip [Callers, Infof]
r := slog.NewRecord(time.Now(), slog.LevelDebug, fmt.Sprintf(format, args...), pcs[0])
_ = Logger.Handler().Handle(context.Background(), r)
}
//
// Info() wraps around slog.Info()
func Info(format string, args ...any) {
if !Logger.Enabled(context.Background(), slog.LevelInfo) {
return
}
var pcs [1]uintptr
runtime.Callers(2, pcs[:]) // skip [Callers, Infof]
r := slog.NewRecord(time.Now(), slog.LevelInfo, format, pcs[0])
r.Add(args...)
_ = Logger.Handler().Handle(context.Background(), r)
}
//
// Infof() provides flexibility to log with the 'printf' style
func Infof(format string, args ...any) {
if !Logger.Enabled(context.Background(), slog.LevelInfo) {
return
}
var pcs [1]uintptr
runtime.Callers(2, pcs[:]) // skip [Callers, Infof]
r := slog.NewRecord(time.Now(), slog.LevelInfo, fmt.Sprintf(format, args...), pcs[0])
_ = Logger.Handler().Handle(context.Background(), r)
}
//
// Warn() wraps around slog.Warn()
func Warn(format string, args ...any) {
if !Logger.Enabled(context.Background(), slog.LevelWarn) {
return
}
var pcs [1]uintptr
runtime.Callers(2, pcs[:]) // skip [Callers, Infof]
r := slog.NewRecord(time.Now(), slog.LevelWarn, format, pcs[0])
r.Add(args...)
_ = Logger.Handler().Handle(context.Background(), r)
}
//
// Warnf() provides flexibility to log with the 'printf' style
func Warnf(format string, args ...any) {
if !Logger.Enabled(context.Background(), slog.LevelWarn) {
return
}
var pcs [1]uintptr
runtime.Callers(2, pcs[:]) // skip [Callers, Infof]
r := slog.NewRecord(time.Now(), slog.LevelWarn, fmt.Sprintf(format, args...), pcs[0])
_ = Logger.Handler().Handle(context.Background(), r)
}
//
// Error() wraps around slog.Error()
func Error(format string, args ...any) {
if !Logger.Enabled(context.Background(), slog.LevelError) {
return
}
var pcs [1]uintptr
runtime.Callers(2, pcs[:]) // skip [Callers, Infof]
r := slog.NewRecord(time.Now(), slog.LevelError, format, pcs[0])
r.Add(args...)
_ = Logger.Handler().Handle(context.Background(), r)
}
//
// Errorf() provides flexibility to log with the 'printf' style
func Errorf(format string, args ...any) {
if !Logger.Enabled(context.Background(), slog.LevelError) {
return
}
var pcs [1]uintptr
runtime.Callers(2, pcs[:]) // skip [Callers, Infof]
r := slog.NewRecord(time.Now(), slog.LevelError, fmt.Sprintf(format, args...), pcs[0])
_ = Logger.Handler().Handle(context.Background(), r)
}
//
// Fatal() exits the main program.
func Fatal(format string, args ...any) {
//func Fatal(format string, args ...any) {
if !Logger.Enabled(context.Background(), LevelFatal) {
return
}
var pcs [1]uintptr
runtime.Callers(2, pcs[:]) // skip [Callers, Infof]
r := slog.NewRecord(time.Now(), LevelFatal, format, pcs[0])
r.Add(args...)
_ = Logger.Handler().Handle(context.Background(), r)
os.Exit(1)
}
//
// Fatalf() provides flexibility to log with the 'printf' style
func Fatalf(format string, args ...any) {
if !Logger.Enabled(context.Background(), LevelFatal) {
return
}
var pcs [1]uintptr
runtime.Callers(2, pcs[:]) // skip [Callers, Infof]
r := slog.NewRecord(time.Now(), LevelFatal, fmt.Sprintf(format, args...), pcs[0])
_ = Logger.Handler().Handle(context.Background(), r)
os.Exit(1)
}
//
// debug = false: INFO level displays INFO, WARN, ERROR, FATAL logs.
// debug = true: DEBUG level displays DEBUG, INFO, WARN, ERROR, FATAL logs.
//
// InitLogging() wraps around a new global logger with level and format.
func InitLogging(debug bool, format string) {
replace := func(groups []string, a slog.Attr) slog.Attr {
if a.Key == slog.SourceKey {
source := a.Value.Any().(*slog.Source)
source.File = filepath.Base(source.File)
}
// Adding a whole new level as Fatal
if a.Key == slog.LevelKey {
a.Key = "level"
level := a.Value.Any().(slog.Level)
if level == LevelFatal {
a.Value = slog.StringValue("FATAL")
}
}
return a
}
if debug == true {
if strings.ToLower(format) == "text" {
Logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{AddSource: true, Level: slog.LevelDebug, ReplaceAttr: replace}))
} else {
Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{AddSource: true, Level: slog.LevelDebug, ReplaceAttr: replace}))
}
} else {
if strings.ToLower(format) == "text" {
Logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{AddSource: true, Level: slog.LevelInfo, ReplaceAttr: replace}))
} else {
Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{AddSource: true, Level: slog.LevelInfo, ReplaceAttr: replace}))
}
}
}