-
Notifications
You must be signed in to change notification settings - Fork 0
/
logger.go
247 lines (216 loc) · 7.34 KB
/
logger.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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
//This file is part of logger. ©2020-2023 Jörg Walter.
// The package logger provides a Logger type that can receive log records. Logger will only display a record if it is as severe as
// or more severe than the loglevel set for the Logger. Users of Logger therefore can control how much logging output they will see
// while running their program. A Logger can be used by multiple goroutines.
//
// For usable loglevels see const.
package logger
import (
"fmt"
"io"
"os"
"strings"
"sync"
"time"
)
// Logger is the data type used for sending log records to.
type Logger struct {
mu *sync.Mutex
delimiter string
timeFormat string
level Level
out io.Writer
}
// New constructs a new Logger. It will print a log record to its given writer if it fulfills the
// Logger's designated loglevel or a more severe one. If you set the level to LevelCritical, the Logger
// will print all messages of LevelPanic or LevelAlert or LevelCritical.
func New(w io.Writer, level Level, delimiter string) *Logger {
if len(delimiter) < 1 {
panic("Programming error: logger.New: Passed empty string as delimiter")
}
if w == nil {
panic("Programming error: logger.New: Passed nil as output writer")
}
assertLoglevel(level)
return &Logger{
delimiter: delimiter,
level: level,
mu: new(sync.Mutex),
out: w,
}
}
// Alert sends a message of loglevel LevelAlert to the Logger.
func (l *Logger) Alert(v ...any) (n int, err error) {
return l.Println(LevelAlert, v...)
}
// Alertf sends a formatted message of loglevel LevelAlert to the Logger.
func (l *Logger) Alertf(format string, a ...any) (n int, err error) {
return l.Printf(LevelAlert, format, a...)
}
// Critical sends a message of loglevel LevelCritical to the Logger.
func (l *Logger) Critical(v ...any) (n int, err error) {
return l.Println(LevelCritical, v...)
}
// Criticalf sends a formatted message of loglevel LevelCritical to the Logger.
func (l *Logger) Criticalf(format string, a ...any) (n int, err error) {
return l.Printf(LevelCritical, format, a...)
}
// Die sends a message of loglevel LevelPanic to the Logger, then exits with code 1.
func (l *Logger) Die(v ...any) {
l.Panic(v...)
os.Exit(1)
}
// Dief sends a formatted message of loglevel LevelPanic to the Logger, then exits with code 1.
func (l *Logger) Dief(format string, a ...any) {
l.Panicf(format, a...)
os.Exit(1)
}
// Debug sends a message of loglevel LevelDebug to the Logger.
func (l *Logger) Debug(v ...any) (n int, err error) {
return l.Println(LevelDebug, v...)
}
// Debugf sends a formatted message of loglevel LevelDebug to the Logger.
func (l *Logger) Debugf(format string, a ...any) (n int, err error) {
return l.Printf(LevelDebug, format, a...)
}
// Error sends a message of loglevel LevelError to the Logger.
func (l *Logger) Error(v ...any) (n int, err error) {
return l.Println(LevelError, v...)
}
// Errorf sends a formatted message of loglevel LevelError to the Logger.
func (l *Logger) Errorf(format string, a ...any) (n int, err error) {
return l.Printf(LevelError, format, a...)
}
// Info sends a message of loglevel LevelInfo to the Logger.
func (l *Logger) Info(v ...any) (n int, err error) {
return l.Println(LevelInfo, v...)
}
// Infof sends a formatted message of loglevel LevelInfo to the Logger.
func (l *Logger) Infof(format string, a ...any) (n int, err error) {
return l.Printf(LevelInfo, format, a...)
}
// Level returns the Logger's current loglevel as an integer.
func (l *Logger) Level() Level {
l.mu.Lock()
defer l.mu.Unlock()
return l.level
}
// Notice sends a message of loglevel LevelNotice to the Logger.
func (l *Logger) Notice(v ...any) (n int, err error) {
return l.Println(LevelNotice, v...)
}
// Noticef sends a formatted message of loglevel LevelNotice to the Logger.
func (l *Logger) Noticef(format string, a ...any) (n int, err error) {
return l.Printf(LevelNotice, format, a...)
}
// Panic sends a message of loglevel LevelPanic to the Logger.
// Please note that it does NOT call panic()!
func (l *Logger) Panic(v ...any) (n int, err error) {
return l.Println(LevelPanic, v...)
}
// Panicf sends a formatted message of loglevel LevelPanic to the Logger.
// Please note that it does NOT call panic()!
func (l *Logger) Panicf(format string, a ...any) (n int, err error) {
return l.Printf(LevelPanic, format, a...)
}
// Println writes the log message if its log level is equally severe or more severe than that set for the Logger.
func (l *Logger) Println(level Level, v ...any) (n int, err error) {
l.mu.Lock()
defer l.mu.Unlock()
if !l.trigger(level) {
return 0, nil
}
if len(l.timeFormat) > 0 {
return fmt.Fprintf(l.out,
"[%s]%s%s%s%s\n",
level.String(),
l.delimiter,
time.Now().Format(l.timeFormat),
l.delimiter,
fmt.Sprint(v...))
} else {
return fmt.Fprintf(l.out,
"[%s]%s%s\n",
level.String(),
l.delimiter,
fmt.Sprint(v...))
}
}
// Printf writes a formatted log message if the logger was configured to print the given level.
func (l *Logger) Printf(level Level, format string, a ...any) (n int, err error) {
l.mu.Lock()
defer l.mu.Unlock()
if !l.trigger(level) {
return 0, nil
}
if len(l.timeFormat) > 0 {
return fmt.Fprintf(l.out,
"[%s]%s%s%s%s",
level.String(),
l.delimiter,
time.Now().Format(l.timeFormat),
l.delimiter,
l.autoAppendLF(fmt.Sprintf(format, a...)))
} else {
return fmt.Fprintf(l.out,
"[%s]%s%s",
level.String(),
l.delimiter,
l.autoAppendLF(fmt.Sprintf(format, a...)))
}
}
// SetLevel sets a new loglevel for the Logger. Setting an invalid loglevel will cause a panic.
func (l *Logger) SetLevel(level Level) {
assertLoglevel(level)
l.mu.Lock()
defer l.mu.Unlock()
l.level = level
}
// SetOutput changes the writer the Logger will write its messages to.
func (l *Logger) SetOutput(w io.Writer) {
if w == nil {
panic("Programming error: (l *Logger) SetOutput(): Passed nil as output writer")
}
l.mu.Lock()
defer l.mu.Unlock()
l.out = w
}
// SetTimeFormat takes a format string as defined in the "(t Time) Format" function of go's "time" module.
// If such a string is set, log records will display a timestamp formatted like specified by the format string.
// To remove timestamps from future log records, set the format string to "".
func (l *Logger) SetTimeFormat(format string) {
l.mu.Lock()
defer l.mu.Unlock()
l.timeFormat = format
}
// TimeFormat returns the current format string for the timestamp. If it returns "", log records will have no timestamp.
func (l *Logger) TimeFormat() string {
l.mu.Lock()
defer l.mu.Unlock()
return l.timeFormat
}
// Warning sends a message of loglevel LevelWarning to the Logger.
func (l *Logger) Warning(v ...any) (n int, err error) {
return l.Println(LevelWarning, v...)
}
// Warningf sends a formatted message of loglevel LevelWarning to the Logger.
func (l *Logger) Warningf(format string, a ...any) (n int, err error) {
return l.Printf(LevelWarning, format, a...)
}
// trigger returns true if the Logger should print a message of loglevel
// level, otherwise it returns false.
func (l *Logger) trigger(lvl Level) bool {
assertLoglevel(lvl)
if lvl <= l.level {
return true
}
return false
}
// autoAppendLF appends one newline character at the end of input and returns
// a new string if input doesn't already end with a newline character.
func (l *Logger) autoAppendLF(input string) string {
if strings.HasSuffix(input, "\n") {
return input
}
return input + "\n"
}