podman
225 строк · 5.4 Кб
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
6package jwalterweatherman
7
8import (
9"fmt"
10"io"
11"io/ioutil"
12"log"
13)
14
15type Threshold int
16
17func (t Threshold) String() string {
18return prefixes[t]
19}
20
21const (
22LevelTrace Threshold = iota
23LevelDebug
24LevelInfo
25LevelWarn
26LevelError
27LevelCritical
28LevelFatal
29)
30
31var prefixes map[Threshold]string = map[Threshold]string{
32LevelTrace: "TRACE",
33LevelDebug: "DEBUG",
34LevelInfo: "INFO",
35LevelWarn: "WARN",
36LevelError: "ERROR",
37LevelCritical: "CRITICAL",
38LevelFatal: "FATAL",
39}
40
41// Notepad is where you leave a note!
42type Notepad struct {
43TRACE *log.Logger
44DEBUG *log.Logger
45INFO *log.Logger
46WARN *log.Logger
47ERROR *log.Logger
48CRITICAL *log.Logger
49FATAL *log.Logger
50
51LOG *log.Logger
52FEEDBACK *Feedback
53
54loggers [7]**log.Logger
55logHandle io.Writer
56outHandle io.Writer
57logThreshold Threshold
58stdoutThreshold Threshold
59prefix string
60flags int
61
62logListeners []LogListener
63}
64
65// A LogListener can ble supplied to a Notepad to listen on log writes for a given
66// threshold. This can be used to capture log events in unit tests and similar.
67// Note that this function will be invoked once for each log threshold. If
68// the given threshold is not of interest to you, return nil.
69// Note that these listeners will receive log events for a given threshold, even
70// if the current configuration says not to log it. That way you can count ERRORs even
71// if you don't print them to the console.
72type LogListener func(t Threshold) io.Writer
73
74// NewNotepad creates a new Notepad.
75func NewNotepad(
76outThreshold Threshold,
77logThreshold Threshold,
78outHandle, logHandle io.Writer,
79prefix string, flags int,
80logListeners ...LogListener,
81) *Notepad {
82
83n := &Notepad{logListeners: logListeners}
84
85n.loggers = [7]**log.Logger{&n.TRACE, &n.DEBUG, &n.INFO, &n.WARN, &n.ERROR, &n.CRITICAL, &n.FATAL}
86n.outHandle = outHandle
87n.logHandle = logHandle
88n.stdoutThreshold = outThreshold
89n.logThreshold = logThreshold
90
91if len(prefix) != 0 {
92n.prefix = "[" + prefix + "] "
93} else {
94n.prefix = ""
95}
96
97n.flags = flags
98
99n.LOG = log.New(n.logHandle,
100"LOG: ",
101n.flags)
102n.FEEDBACK = &Feedback{out: log.New(outHandle, "", 0), log: n.LOG}
103
104n.init()
105return n
106}
107
108// init creates the loggers for each level depending on the notepad thresholds.
109func (n *Notepad) init() {
110logAndOut := io.MultiWriter(n.outHandle, n.logHandle)
111
112for t, logger := range n.loggers {
113threshold := Threshold(t)
114prefix := n.prefix + threshold.String() + " "
115
116switch {
117case threshold >= n.logThreshold && threshold >= n.stdoutThreshold:
118*logger = log.New(n.createLogWriters(threshold, logAndOut), prefix, n.flags)
119
120case threshold >= n.logThreshold:
121*logger = log.New(n.createLogWriters(threshold, n.logHandle), prefix, n.flags)
122
123case threshold >= n.stdoutThreshold:
124*logger = log.New(n.createLogWriters(threshold, n.outHandle), prefix, n.flags)
125
126default:
127*logger = log.New(n.createLogWriters(threshold, ioutil.Discard), prefix, n.flags)
128}
129}
130}
131
132func (n *Notepad) createLogWriters(t Threshold, handle io.Writer) io.Writer {
133if len(n.logListeners) == 0 {
134return handle
135}
136writers := []io.Writer{handle}
137for _, l := range n.logListeners {
138w := l(t)
139if w != nil {
140writers = append(writers, w)
141}
142}
143
144if len(writers) == 1 {
145return handle
146}
147
148return io.MultiWriter(writers...)
149}
150
151// SetLogThreshold changes the threshold above which messages are written to the
152// log file.
153func (n *Notepad) SetLogThreshold(threshold Threshold) {
154n.logThreshold = threshold
155n.init()
156}
157
158// SetLogOutput changes the file where log messages are written.
159func (n *Notepad) SetLogOutput(handle io.Writer) {
160n.logHandle = handle
161n.init()
162}
163
164// GetStdoutThreshold returns the defined Treshold for the log logger.
165func (n *Notepad) GetLogThreshold() Threshold {
166return n.logThreshold
167}
168
169// SetStdoutThreshold changes the threshold above which messages are written to the
170// standard output.
171func (n *Notepad) SetStdoutThreshold(threshold Threshold) {
172n.stdoutThreshold = threshold
173n.init()
174}
175
176// GetStdoutThreshold returns the Treshold for the stdout logger.
177func (n *Notepad) GetStdoutThreshold() Threshold {
178return n.stdoutThreshold
179}
180
181// SetPrefix changes the prefix used by the notepad. Prefixes are displayed between
182// brackets at the beginning of the line. An empty prefix won't be displayed at all.
183func (n *Notepad) SetPrefix(prefix string) {
184if len(prefix) != 0 {
185n.prefix = "[" + prefix + "] "
186} else {
187n.prefix = ""
188}
189n.init()
190}
191
192// SetFlags choose which flags the logger will display (after prefix and message
193// level). See the package log for more informations on this.
194func (n *Notepad) SetFlags(flags int) {
195n.flags = flags
196n.init()
197}
198
199// Feedback writes plainly to the outHandle while
200// logging with the standard extra information (date, file, etc).
201type Feedback struct {
202out *log.Logger
203log *log.Logger
204}
205
206func (fb *Feedback) Println(v ...interface{}) {
207fb.output(fmt.Sprintln(v...))
208}
209
210func (fb *Feedback) Printf(format string, v ...interface{}) {
211fb.output(fmt.Sprintf(format, v...))
212}
213
214func (fb *Feedback) Print(v ...interface{}) {
215fb.output(fmt.Sprint(v...))
216}
217
218func (fb *Feedback) output(s string) {
219if fb.out != nil {
220fb.out.Output(2, s)
221}
222if fb.log != nil {
223fb.log.Output(2, s)
224}
225}
226