Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
225 lines
5.4 KiB
225 lines
5.4 KiB
// Copyright © 2016 Steve Francia <spf@spf13.com>. |
|
// |
|
// Use of this source code is governed by an MIT-style |
|
// license that can be found in the LICENSE file. |
|
|
|
package jwalterweatherman |
|
|
|
import ( |
|
"fmt" |
|
"io" |
|
"io/ioutil" |
|
"log" |
|
) |
|
|
|
type Threshold int |
|
|
|
func (t Threshold) String() string { |
|
return prefixes[t] |
|
} |
|
|
|
const ( |
|
LevelTrace Threshold = iota |
|
LevelDebug |
|
LevelInfo |
|
LevelWarn |
|
LevelError |
|
LevelCritical |
|
LevelFatal |
|
) |
|
|
|
var prefixes map[Threshold]string = map[Threshold]string{ |
|
LevelTrace: "TRACE", |
|
LevelDebug: "DEBUG", |
|
LevelInfo: "INFO", |
|
LevelWarn: "WARN", |
|
LevelError: "ERROR", |
|
LevelCritical: "CRITICAL", |
|
LevelFatal: "FATAL", |
|
} |
|
|
|
// Notepad is where you leave a note! |
|
type Notepad struct { |
|
TRACE *log.Logger |
|
DEBUG *log.Logger |
|
INFO *log.Logger |
|
WARN *log.Logger |
|
ERROR *log.Logger |
|
CRITICAL *log.Logger |
|
FATAL *log.Logger |
|
|
|
LOG *log.Logger |
|
FEEDBACK *Feedback |
|
|
|
loggers [7]**log.Logger |
|
logHandle io.Writer |
|
outHandle io.Writer |
|
logThreshold Threshold |
|
stdoutThreshold Threshold |
|
prefix string |
|
flags int |
|
|
|
logListeners []LogListener |
|
} |
|
|
|
// A LogListener can ble supplied to a Notepad to listen on log writes for a given |
|
// threshold. This can be used to capture log events in unit tests and similar. |
|
// Note that this function will be invoked once for each log threshold. If |
|
// the given threshold is not of interest to you, return nil. |
|
// Note that these listeners will receive log events for a given threshold, even |
|
// if the current configuration says not to log it. That way you can count ERRORs even |
|
// if you don't print them to the console. |
|
type LogListener func(t Threshold) io.Writer |
|
|
|
// NewNotepad creates a new Notepad. |
|
func NewNotepad( |
|
outThreshold Threshold, |
|
logThreshold Threshold, |
|
outHandle, logHandle io.Writer, |
|
prefix string, flags int, |
|
logListeners ...LogListener, |
|
) *Notepad { |
|
|
|
n := &Notepad{logListeners: logListeners} |
|
|
|
n.loggers = [7]**log.Logger{&n.TRACE, &n.DEBUG, &n.INFO, &n.WARN, &n.ERROR, &n.CRITICAL, &n.FATAL} |
|
n.outHandle = outHandle |
|
n.logHandle = logHandle |
|
n.stdoutThreshold = outThreshold |
|
n.logThreshold = logThreshold |
|
|
|
if len(prefix) != 0 { |
|
n.prefix = "[" + prefix + "] " |
|
} else { |
|
n.prefix = "" |
|
} |
|
|
|
n.flags = flags |
|
|
|
n.LOG = log.New(n.logHandle, |
|
"LOG: ", |
|
n.flags) |
|
n.FEEDBACK = &Feedback{out: log.New(outHandle, "", 0), log: n.LOG} |
|
|
|
n.init() |
|
return n |
|
} |
|
|
|
// init creates the loggers for each level depending on the notepad thresholds. |
|
func (n *Notepad) init() { |
|
logAndOut := io.MultiWriter(n.outHandle, n.logHandle) |
|
|
|
for t, logger := range n.loggers { |
|
threshold := Threshold(t) |
|
prefix := n.prefix + threshold.String() + " " |
|
|
|
switch { |
|
case threshold >= n.logThreshold && threshold >= n.stdoutThreshold: |
|
*logger = log.New(n.createLogWriters(threshold, logAndOut), prefix, n.flags) |
|
|
|
case threshold >= n.logThreshold: |
|
*logger = log.New(n.createLogWriters(threshold, n.logHandle), prefix, n.flags) |
|
|
|
case threshold >= n.stdoutThreshold: |
|
*logger = log.New(n.createLogWriters(threshold, n.outHandle), prefix, n.flags) |
|
|
|
default: |
|
*logger = log.New(n.createLogWriters(threshold, ioutil.Discard), prefix, n.flags) |
|
} |
|
} |
|
} |
|
|
|
func (n *Notepad) createLogWriters(t Threshold, handle io.Writer) io.Writer { |
|
if len(n.logListeners) == 0 { |
|
return handle |
|
} |
|
writers := []io.Writer{handle} |
|
for _, l := range n.logListeners { |
|
w := l(t) |
|
if w != nil { |
|
writers = append(writers, w) |
|
} |
|
} |
|
|
|
if len(writers) == 1 { |
|
return handle |
|
} |
|
|
|
return io.MultiWriter(writers...) |
|
} |
|
|
|
// SetLogThreshold changes the threshold above which messages are written to the |
|
// log file. |
|
func (n *Notepad) SetLogThreshold(threshold Threshold) { |
|
n.logThreshold = threshold |
|
n.init() |
|
} |
|
|
|
// SetLogOutput changes the file where log messages are written. |
|
func (n *Notepad) SetLogOutput(handle io.Writer) { |
|
n.logHandle = handle |
|
n.init() |
|
} |
|
|
|
// GetStdoutThreshold returns the defined Treshold for the log logger. |
|
func (n *Notepad) GetLogThreshold() Threshold { |
|
return n.logThreshold |
|
} |
|
|
|
// SetStdoutThreshold changes the threshold above which messages are written to the |
|
// standard output. |
|
func (n *Notepad) SetStdoutThreshold(threshold Threshold) { |
|
n.stdoutThreshold = threshold |
|
n.init() |
|
} |
|
|
|
// GetStdoutThreshold returns the Treshold for the stdout logger. |
|
func (n *Notepad) GetStdoutThreshold() Threshold { |
|
return n.stdoutThreshold |
|
} |
|
|
|
// SetPrefix changes the prefix used by the notepad. Prefixes are displayed between |
|
// brackets at the beginning of the line. An empty prefix won't be displayed at all. |
|
func (n *Notepad) SetPrefix(prefix string) { |
|
if len(prefix) != 0 { |
|
n.prefix = "[" + prefix + "] " |
|
} else { |
|
n.prefix = "" |
|
} |
|
n.init() |
|
} |
|
|
|
// SetFlags choose which flags the logger will display (after prefix and message |
|
// level). See the package log for more informations on this. |
|
func (n *Notepad) SetFlags(flags int) { |
|
n.flags = flags |
|
n.init() |
|
} |
|
|
|
// Feedback writes plainly to the outHandle while |
|
// logging with the standard extra information (date, file, etc). |
|
type Feedback struct { |
|
out *log.Logger |
|
log *log.Logger |
|
} |
|
|
|
func (fb *Feedback) Println(v ...interface{}) { |
|
fb.output(fmt.Sprintln(v...)) |
|
} |
|
|
|
func (fb *Feedback) Printf(format string, v ...interface{}) { |
|
fb.output(fmt.Sprintf(format, v...)) |
|
} |
|
|
|
func (fb *Feedback) Print(v ...interface{}) { |
|
fb.output(fmt.Sprint(v...)) |
|
} |
|
|
|
func (fb *Feedback) output(s string) { |
|
if fb.out != nil { |
|
fb.out.Output(2, s) |
|
} |
|
if fb.log != nil { |
|
fb.log.Output(2, s) |
|
} |
|
}
|
|
|