forked from peak/s5cmd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
log.go
129 lines (110 loc) · 2.39 KB
/
log.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
package log
import (
"fmt"
"os"
)
// output is an internal container for messages to be logged.
type output struct {
std *os.File
message string
}
// outputCh is used to synchronize writes to standard output. Multi-line
// logging is not possible if all workers print logs at the same time.
var outputCh = make(chan output, 10000)
var global *Logger
// Init inits global logger.
func Init(level string, json bool) {
global = New(level, json)
}
// Debug prints message in debug mode.
func Debug(msg Message) {
global.printf(levelDebug, msg, os.Stdout)
}
// Info prints message in info mode.
func Info(msg Message) {
global.printf(levelInfo, msg, os.Stdout)
}
// Error prints message in error mode.
func Error(msg Message) {
global.printf(levelError, msg, os.Stderr)
}
// Close closes logger and its channel.
func Close() {
close(outputCh)
<-global.donech
}
// Logger is a structure for logging messages.
type Logger struct {
donech chan struct{}
json bool
level logLevel
}
// New creates new logger.
func New(level string, json bool) *Logger {
logLevel := levelFromString(level)
logger := &Logger{
donech: make(chan struct{}),
json: json,
level: logLevel,
}
go logger.out()
return logger
}
// printf prints message according to the given level, message and std mode.
func (l *Logger) printf(level logLevel, message Message, std *os.File) {
if level < l.level {
return
}
if l.json {
outputCh <- output{
message: message.JSON(),
std: std,
}
} else {
outputCh <- output{
message: fmt.Sprintf("%v%v", level, message.String()),
std: std,
}
}
}
// out listens for outputCh and logs messages.
func (l *Logger) out() {
defer close(l.donech)
for output := range outputCh {
_, _ = fmt.Fprintln(output.std, output.message)
}
}
// logLevel is the level of Logger.
type logLevel int
const (
levelDebug logLevel = iota
levelInfo
levelError
)
// String returns the string representation of logLevel.
func (l logLevel) String() string {
switch l {
case levelInfo:
return ""
case levelError:
return "ERROR "
case levelDebug:
return "DEBUG "
default:
return "UNKNOWN "
}
}
// levelFromString returns logLevel for given string. It
// return `levelInfo` as a default.
func levelFromString(s string) logLevel {
switch s {
case "debug":
return levelDebug
case "info":
return levelInfo
case "error":
return levelError
default:
return levelInfo
}
}