-
Notifications
You must be signed in to change notification settings - Fork 0
/
logl.go
276 lines (245 loc) · 6.76 KB
/
logl.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
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
// Package logl implements logging at levels from NONE to DEBUG,
// The output is filtered by a globally set logging level.
// The objective was to write a logging package that is small and simple.
// The alternatives I looked at were either larger and more complex than my
// applications, or did not do what I required.
// To do this logl wraps an instance of log.Logger and calls the relevant
// functions in log to write the mesages.
package logl
import (
"bufio"
"encoding/json"
"fmt"
"io"
"log"
"os"
)
type Level int
const (
NONE Level = iota
ERROR
WARN
INFO
DEBUG
TRACE
)
var toString = map[Level]string{
NONE: "NONE",
ERROR: "ERROR",
WARN: "WARN",
INFO: "INFO",
DEBUG: "DEBUG",
TRACE: "TRACE",
}
var toId = map[string]Level{
"NONE": NONE,
"ERROR": ERROR,
"WARN": WARN,
"INFO": INFO,
"DEBUG": DEBUG,
"TRACE": TRACE,
}
func (l Level) String() string {
return toString[l]
}
// MarshalJSON marshals the Level as a quoted json string
func (l Level) MarshalJSON() ([]byte, error) {
// buf := bytes.NewBufferString(`"`)
// buf.WriteString(toString[l])
// buf.WriteString(`"`)
// return buf.Bytes(), nil
return []byte(fmt.Sprintf("%q", toString[l])), nil
}
// UnmarshalJSON unmashals a quoted json string to the Level value
func (l *Level) UnmarshalJSON(b []byte) error {
var s string
err := json.Unmarshal(b, &s)
if err != nil {
return err
}
// if the string is not foound set it to INFO
if id, ok := toId[s]; ok {
*l = id
} else {
*l = INFO
}
return nil
}
// For conveniance these are copied from the log code.
// These flags define which text to prefix to each log entry generated by the Logger.
// Bits are or'ed together to control what's printed.
// With the exception of the Lmsgprefix flag, there is no
// control over the order they appear (the order listed here)
// or the format they present (as described in the comments).
// The prefix is followed by a colon only when Llongfile or Lshortfile
// is specified.
// For example, flags Ldate | Ltime (or LstdFlags) produce,
// 2009/01/23 01:23:23 message
// while flags Ldate | Ltime | Lmicroseconds | Llongfile produce,
// 2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
const (
Ldate = 1 << iota // the date in the local time zone: 2009/01/23
Ltime // the time in the local time zone: 01:23:23
Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.
Llongfile // full file name and line number: /a/b/c/d.go:23
Lshortfile // final file name element and line number: d.go:23. overrides Llongfile
LUTC // if Ldate or Ltime is set, use UTC rather than the local time zone
Lmsgprefix // move the "prefix" from the beginning of the line to before the message
LstdFlags = Ldate | Ltime // initial values for the standard logger
)
var (
level Level
file *os.File
writer io.Writer
)
// Called at load time and creates an new instance of log.Logger writing to StdOut and with flags LstdFlags|Lshortfile
func init() {
log.SetFlags(LstdFlags | Lshortfile)
level = INFO
}
// Flushes the output stream
func Flush() {
if writer != nil {
if b, ok := writer.(*bufio.Writer); ok {
b.Flush()
}
}
}
// Flushes and closes the output stream
// Sets the output stream to the default os.Stderr
func Close() {
Flush()
if file != nil {
file.Close()
}
SetWriterStderr()
}
// Set the minimum logging level NONE ... DEBUG
func SetLevel(l Level) {
level = l
}
// The current logging level
func GetLevel() Level {
return level
}
// Set the io.writer to os.Stderr (the defalut writer)
func SetWriterStderr() {
writer = nil
log.SetOutput(os.Stderr)
}
// Set the io.writer for log.Logger
func SetWriter(out io.Writer) {
writer = out // so we can handle flushes on close
log.SetOutput(out)
}
// Set the io.writer to write to the file specified
func SetFileWriter(fileName string, truncate bool) error {
var err error
flags := os.O_CREATE | os.O_WRONLY | os.O_APPEND
if truncate {
flags = flags | os.O_TRUNC
}
file, err = os.OpenFile(fileName, flags, 0666)
if err != nil {
return err
}
writer = bufio.NewWriter(file)
log.SetOutput(writer)
return nil
}
// Set the output flags for log.Logger
func SetFlags(flag int) {
log.SetFlags(flag)
}
// Logs at the TRACE level, see Info() for details
func Trace(v ...interface{}) {
if level < DEBUG {
return
}
log.Output(2, "[TRACE] "+fmt.Sprint(v...))
}
// Logs at the DEBUG level, see Info() for details
func Debug(v ...interface{}) {
if level < DEBUG {
return
}
log.Output(2, "[DEBUG] "+fmt.Sprint(v...))
}
// Write a log message at the INFO level, but only if the logging level is INFO or higher.
// The message supplied will be prefixed with the logging level
func Info(v ...interface{}) {
if level < INFO {
return
}
log.Output(2, "[INFO] "+fmt.Sprint(v...))
}
// Logs at the WARN level, see Info() for details
func Warn(v ...interface{}) {
if level < WARN {
return
}
log.Output(2, "[WARN] "+fmt.Sprint(v...))
}
// Logs at the ERROR level, see Info() for details
func Error(v ...interface{}) {
if level < ERROR {
return
}
log.Output(2, "[ERROR] "+fmt.Sprint(v...))
}
// Logs at the FATAL level, calls Close() then terminates using os.Exit(1).
// Only use if you really have to!
// See Info() for details
func Fatal(v ...interface{}) {
log.Output(2, "[FATAL] "+fmt.Sprint(v...))
Close()
os.Exit(1)
}
// Logs at the TRACE level, see Info() for details
// Arguments are handled in the manner of fmt.Printf.
func Tracef(f string, v ...interface{}) {
if level < TRACE {
return
}
log.Output(2, "[TRACE] "+fmt.Sprintf(f, v...))
}
// Logs at the DEBUG level, see Info() for details
// Arguments are handled in the manner of fmt.Printf.
func Debugf(f string, v ...interface{}) {
if level < DEBUG {
return
}
log.Output(2, "[DEBUG] "+fmt.Sprintf(f, v...))
}
// Logs at the INFO level, see Info() for details
// Arguments are handled in the manner of fmt.Printf.
func Infof(f string, v ...interface{}) {
if level < INFO {
return
}
log.Output(2, "[INFO] "+fmt.Sprintf(f, v...))
}
// Logs at the WARN level, see Info() for details
// Arguments are handled in the manner of fmt.Printf.
func Warnf(f string, v ...interface{}) {
if level < WARN {
return
}
log.Output(2, "[WARN] "+fmt.Sprintf(f, v...))
}
// Logs at the ERROR level, see Info() for details
// Arguments are handled in the manner of fmt.Printf.
func Errorf(f string, v ...interface{}) {
if level < ERROR {
return
}
log.Output(2, "[ERROR] "+fmt.Sprintf(f, v...))
}
// Logs at the FTL level, calls Close() then terminates using os.Exit(1).
// Only use if you really have to!
// Arguments are handled in the manner of fmt.Printf. See Info() for details
func Fatalf(f string, v ...interface{}) {
log.Output(2, "[FATAL] "+fmt.Sprintf(f, v...))
Close()
os.Exit(1)
}