123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- // 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)
- }
- }
|