-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlogger.go
164 lines (142 loc) · 3.99 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
package reql
import (
"errors"
"fmt"
"io"
"os"
"strings"
)
// Logger represents a standard level logging interface. Every method logs the provided
// message using fmt.Printf with a timestamp and level prefix. Fatal logs the message
// like the other methods, but calls os.Exit(1) afterwards.
type Logger interface {
// Logs at the LevelDebug level.
Debug(format string, args ...interface{})
// Logs at the LevelInfo level.
Info(format string, args ...interface{})
// Logs at the LevelWarn level.
Warn(format string, args ...interface{})
// Logs at the LevelError level.
Error(format string, args ...interface{})
// Logs at the LevelFatal level then calls os.Exit(1).
Fatal(format string, args ...interface{})
}
// Level represents a logging level. This restricts the logger to print only messages with
// at least this level.
type Level int
// The available logging levels.
const (
LevelDebug Level = iota
LevelInfo
LevelWarn
LevelError
LevelFatal
)
func (l Level) String() string {
switch l {
case LevelDebug:
return "DEBUG"
case LevelInfo:
return "INFO"
case LevelWarn:
return "WARN"
case LevelError:
return "ERROR"
case LevelFatal:
return "FATAL"
}
return fmt.Sprintf("%%!(Level=%d)", l)
}
// ParseLevel converts a string to the corresponding Level. Comparisons are case insensitive.
// If an unknown level is provided, then an error will be returned.
func ParseLevel(l string) (Level, error) {
switch strings.ToLower(l) {
case "debug":
return LevelDebug, nil
case "info":
return LevelInfo, nil
case "warn":
return LevelWarn, nil
case "error":
return LevelError, nil
case "fatal":
return LevelFatal, nil
}
return Level(-1), errors.New("invalid log level")
}
func (l Level) validate() error {
if strings.HasPrefix(l.String(), "%!") {
return errors.New("invalid Level")
}
return nil
}
// LevelLogger implements the Logger interface using the defined Level constants. The provided
// level is treated as the minimum. Any messages passed to a level that is at least the defined
// level will be printed.
//
// Every log message is treated as a single line. If there is no newline at the end of the
// message, then one will be added.
type LevelLogger struct {
w io.Writer
level Level
}
// NewLevelLogger constructs a new logger. An error will be returned if an invalid level is
// provided. If no output writer is provided, then os.Stdout will be used.
func NewLevelLogger(level Level, out io.Writer) (*LevelLogger, error) {
if err := level.validate(); err != nil {
return nil, err
}
if out == nil {
out = os.Stdout
}
return &LevelLogger{
w: out,
level: level,
}, nil
}
// Logs at the LevelDebug level.
func (l *LevelLogger) Debug(format string, args ...interface{}) {
if l.level <= LevelDebug {
l.printPrefixTag(LevelDebug)
l.printMessage([]byte(fmt.Sprintf(format, args...)))
}
}
// Logs at the LevelInfo level.
func (l *LevelLogger) Info(format string, args ...interface{}) {
if l.level <= LevelInfo {
l.printPrefixTag(LevelInfo)
l.printMessage([]byte(fmt.Sprintf(format, args...)))
}
}
// Logs at the LevelWarn level.
func (l *LevelLogger) Warn(format string, args ...interface{}) {
if l.level <= LevelWarn {
l.printPrefixTag(LevelWarn)
l.printMessage([]byte(fmt.Sprintf(format, args...)))
}
}
// Logs at the LevelError level.
func (l *LevelLogger) Error(format string, args ...interface{}) {
if l.level <= LevelError {
l.printPrefixTag(LevelError)
l.printMessage([]byte(fmt.Sprintf(format, args...)))
}
}
// Logs at the LevelFatal level then calls os.Exit(1).
func (l *LevelLogger) Fatal(format string, args ...interface{}) {
if l.level <= LevelFatal {
l.printPrefixTag(LevelFatal)
l.printMessage([]byte(fmt.Sprintf(format, args...)))
os.Exit(1)
}
}
func (l *LevelLogger) printPrefixTag(level Level) {
l.w.Write([]byte(fmt.Sprintf("[%s]: ", level)))
}
var newline = []byte{'\n'}
func (l *LevelLogger) printMessage(message []byte) {
l.w.Write(message)
if len(message) == 0 || message[len(message)-1] != '\n' {
l.w.Write(newline)
}
}