|
1 // Copyright © 2016 Steve Francia <spf@spf13.com>. |
|
2 // |
|
3 // Use of this source code is governed by an MIT-style |
|
4 // license that can be found in the LICENSE file. |
|
5 |
|
6 package jwalterweatherman |
|
7 |
|
8 import ( |
|
9 "fmt" |
|
10 "io" |
|
11 "log" |
|
12 ) |
|
13 |
|
14 type Threshold int |
|
15 |
|
16 func (t Threshold) String() string { |
|
17 return prefixes[t] |
|
18 } |
|
19 |
|
20 const ( |
|
21 LevelTrace Threshold = iota |
|
22 LevelDebug |
|
23 LevelInfo |
|
24 LevelWarn |
|
25 LevelError |
|
26 LevelCritical |
|
27 LevelFatal |
|
28 ) |
|
29 |
|
30 var prefixes map[Threshold]string = map[Threshold]string{ |
|
31 LevelTrace: "TRACE", |
|
32 LevelDebug: "DEBUG", |
|
33 LevelInfo: "INFO", |
|
34 LevelWarn: "WARN", |
|
35 LevelError: "ERROR", |
|
36 LevelCritical: "CRITICAL", |
|
37 LevelFatal: "FATAL", |
|
38 } |
|
39 |
|
40 // Notepad is where you leave a note! |
|
41 type Notepad struct { |
|
42 TRACE *log.Logger |
|
43 DEBUG *log.Logger |
|
44 INFO *log.Logger |
|
45 WARN *log.Logger |
|
46 ERROR *log.Logger |
|
47 CRITICAL *log.Logger |
|
48 FATAL *log.Logger |
|
49 |
|
50 LOG *log.Logger |
|
51 FEEDBACK *Feedback |
|
52 |
|
53 loggers [7]**log.Logger |
|
54 logHandle io.Writer |
|
55 outHandle io.Writer |
|
56 logThreshold Threshold |
|
57 stdoutThreshold Threshold |
|
58 prefix string |
|
59 flags int |
|
60 |
|
61 // One per Threshold |
|
62 logCounters [7]*logCounter |
|
63 } |
|
64 |
|
65 // NewNotepad create a new notepad. |
|
66 func NewNotepad(outThreshold Threshold, logThreshold Threshold, outHandle, logHandle io.Writer, prefix string, flags int) *Notepad { |
|
67 n := &Notepad{} |
|
68 |
|
69 n.loggers = [7]**log.Logger{&n.TRACE, &n.DEBUG, &n.INFO, &n.WARN, &n.ERROR, &n.CRITICAL, &n.FATAL} |
|
70 n.outHandle = outHandle |
|
71 n.logHandle = logHandle |
|
72 n.stdoutThreshold = outThreshold |
|
73 n.logThreshold = logThreshold |
|
74 |
|
75 if len(prefix) != 0 { |
|
76 n.prefix = "[" + prefix + "] " |
|
77 } else { |
|
78 n.prefix = "" |
|
79 } |
|
80 |
|
81 n.flags = flags |
|
82 |
|
83 n.LOG = log.New(n.logHandle, |
|
84 "LOG: ", |
|
85 n.flags) |
|
86 n.FEEDBACK = &Feedback{out: log.New(outHandle, "", 0), log: n.LOG} |
|
87 |
|
88 n.init() |
|
89 return n |
|
90 } |
|
91 |
|
92 // init creates the loggers for each level depending on the notepad thresholds. |
|
93 func (n *Notepad) init() { |
|
94 logAndOut := io.MultiWriter(n.outHandle, n.logHandle) |
|
95 |
|
96 for t, logger := range n.loggers { |
|
97 threshold := Threshold(t) |
|
98 counter := &logCounter{} |
|
99 n.logCounters[t] = counter |
|
100 prefix := n.prefix + threshold.String() + " " |
|
101 |
|
102 switch { |
|
103 case threshold >= n.logThreshold && threshold >= n.stdoutThreshold: |
|
104 *logger = log.New(io.MultiWriter(counter, logAndOut), prefix, n.flags) |
|
105 |
|
106 case threshold >= n.logThreshold: |
|
107 *logger = log.New(io.MultiWriter(counter, n.logHandle), prefix, n.flags) |
|
108 |
|
109 case threshold >= n.stdoutThreshold: |
|
110 *logger = log.New(io.MultiWriter(counter, n.outHandle), prefix, n.flags) |
|
111 |
|
112 default: |
|
113 // counter doesn't care about prefix and flags, so don't use them |
|
114 // for performance. |
|
115 *logger = log.New(counter, "", 0) |
|
116 } |
|
117 } |
|
118 } |
|
119 |
|
120 // SetLogThreshold changes the threshold above which messages are written to the |
|
121 // log file. |
|
122 func (n *Notepad) SetLogThreshold(threshold Threshold) { |
|
123 n.logThreshold = threshold |
|
124 n.init() |
|
125 } |
|
126 |
|
127 // SetLogOutput changes the file where log messages are written. |
|
128 func (n *Notepad) SetLogOutput(handle io.Writer) { |
|
129 n.logHandle = handle |
|
130 n.init() |
|
131 } |
|
132 |
|
133 // GetStdoutThreshold returns the defined Treshold for the log logger. |
|
134 func (n *Notepad) GetLogThreshold() Threshold { |
|
135 return n.logThreshold |
|
136 } |
|
137 |
|
138 // SetStdoutThreshold changes the threshold above which messages are written to the |
|
139 // standard output. |
|
140 func (n *Notepad) SetStdoutThreshold(threshold Threshold) { |
|
141 n.stdoutThreshold = threshold |
|
142 n.init() |
|
143 } |
|
144 |
|
145 // GetStdoutThreshold returns the Treshold for the stdout logger. |
|
146 func (n *Notepad) GetStdoutThreshold() Threshold { |
|
147 return n.stdoutThreshold |
|
148 } |
|
149 |
|
150 // SetPrefix changes the prefix used by the notepad. Prefixes are displayed between |
|
151 // brackets at the beginning of the line. An empty prefix won't be displayed at all. |
|
152 func (n *Notepad) SetPrefix(prefix string) { |
|
153 if len(prefix) != 0 { |
|
154 n.prefix = "[" + prefix + "] " |
|
155 } else { |
|
156 n.prefix = "" |
|
157 } |
|
158 n.init() |
|
159 } |
|
160 |
|
161 // SetFlags choose which flags the logger will display (after prefix and message |
|
162 // level). See the package log for more informations on this. |
|
163 func (n *Notepad) SetFlags(flags int) { |
|
164 n.flags = flags |
|
165 n.init() |
|
166 } |
|
167 |
|
168 // Feedback writes plainly to the outHandle while |
|
169 // logging with the standard extra information (date, file, etc). |
|
170 type Feedback struct { |
|
171 out *log.Logger |
|
172 log *log.Logger |
|
173 } |
|
174 |
|
175 func (fb *Feedback) Println(v ...interface{}) { |
|
176 fb.output(fmt.Sprintln(v...)) |
|
177 } |
|
178 |
|
179 func (fb *Feedback) Printf(format string, v ...interface{}) { |
|
180 fb.output(fmt.Sprintf(format, v...)) |
|
181 } |
|
182 |
|
183 func (fb *Feedback) Print(v ...interface{}) { |
|
184 fb.output(fmt.Sprint(v...)) |
|
185 } |
|
186 |
|
187 func (fb *Feedback) output(s string) { |
|
188 if fb.out != nil { |
|
189 fb.out.Output(2, s) |
|
190 } |
|
191 if fb.log != nil { |
|
192 fb.log.Output(2, s) |
|
193 } |
|
194 } |