diff --git a/logging/example/example.go b/logging/example/example.go index 777eac6..ef53ab2 100644 --- a/logging/example/example.go +++ b/logging/example/example.go @@ -8,13 +8,17 @@ import ( ) var log = logging.Init() -var olog = logging.New("subsystem #42", logging.LevelNotice) +var olog, _ = logging.New("subsystem #42", logging.LevelNotice) func main() { exampleNewWriters() log.Notice("Hello, world.") log.Warning("this program is about to end") + log.SetLevel(logging.LevelDebug) + log.Debug("hello world") + log.SetLevel(logging.LevelNotice) + olog.Print("now online") logging.Suppress("olog") olog.Print("extraneous information") @@ -41,7 +45,7 @@ func exampleNewWriters() { o := testio.NewBufCloser(nil) e := testio.NewBufCloser(nil) - wlog := logging.NewFromWriters("writers", logging.DefaultLevel, o, e) + wlog, _ := logging.NewFromWriters("writers", logging.DefaultLevel, o, e) wlog.Notice("hello, world") wlog.Notice("some more things happening") wlog.Warning("something suspicious has happened") diff --git a/logging/levels.go b/logging/levels.go index 8efd583..1b9b0fa 100644 --- a/logging/levels.go +++ b/logging/levels.go @@ -3,6 +3,7 @@ package logging import ( "fmt" "os" + "runtime" "time" ) @@ -43,6 +44,24 @@ const ( LevelFatal ) +// Cheap integer to fixed-width decimal ASCII. Give a negative width +// to avoid zero-padding. (From log/log.go in the standard library). +func itoa(i int, wid int) string { + // Assemble decimal in reverse order. + var b [20]byte + bp := len(b) - 1 + for i >= 10 || wid > 1 { + wid-- + q := i / 10 + b[bp] = byte('0' + i - q*10) + bp-- + i = q + } + // i < 10 + b[bp] = byte('0' + i) + return string(b[bp:]) +} + func writeToOut(level Level) bool { if level < LevelWarning { return true @@ -69,9 +88,17 @@ func (l *Logger) outputf(level Level, format string, v []interface{}) { } if level >= l.level { + domain := l.domain + if level == LevelDebug { + _, file, line, ok := runtime.Caller(2) + if ok { + domain += " " + file + ":" + itoa(line, -1) + } + } + format = fmt.Sprintf("%s %s: %s%s\n", time.Now().Format(DateFormat), - l.domain, levelPrefix[level], format) + domain, levelPrefix[level], format) if writeToOut(level) { fmt.Fprintf(l.out, format, v...) } else { @@ -86,9 +113,17 @@ func (l *Logger) output(level Level, v []interface{}) { } if level >= l.level { + domain := l.domain + if level == LevelDebug { + _, file, line, ok := runtime.Caller(2) + if ok { + domain += " " + file + ":" + itoa(line, -1) + } + } + format := fmt.Sprintf("%s %s: %s", time.Now().Format(DateFormat), - l.domain, levelPrefix[level]) + domain, levelPrefix[level]) if writeToOut(level) { fmt.Fprintf(l.out, format) fmt.Fprintln(l.out, v...) @@ -179,7 +214,8 @@ func (l *Logger) Info(v ...interface{}) { } // Debugf logs a formatted message at the "debug" level. The arguments -// are handled in the same manner as fmt.Printf. +// are handled in the same manner as fmt.Printf. Note that debug +// logging will print the current func (l *Logger) Debugf(format string, v ...interface{}) { l.outputf(LevelDebug, format, v) } diff --git a/logging/log.go b/logging/log.go index a7e7df9..41606e4 100644 --- a/logging/log.go +++ b/logging/log.go @@ -1,8 +1,15 @@ -// Package logging is an adaptation of the CFSSL logging library. It -// operates on domains, which are components for which logging can be -// selectively enabled or disabled. It also differentiates between -// normal messages (which are sent to standard output) and errors, -// which are sent to standard error. +// Package logging provides domain-based logging in the same style as +// sylog. Domains are some name for which logging can be selectively +// enabled or disabled. Logging also differentiates between normal +// messages (which are sent to standard output) and errors, which are +// sent to standard error; debug messages will also include the file +// and line number. +// +// Domains are intended for identifying logging subystems. A domain +// can be suppressed with Suppress, and re-enabled with Enable. There +// are prefixed versions of these as well. +// +// This package was adapted from the CFSSL logging code. package logging import ( @@ -159,6 +166,10 @@ func NewFromWriters(domain string, level Level, w, e io.WriteCloser) (l *Logger, return l, true } + if w == nil { + w = os.Stdout + } + if e == nil { e = w } @@ -179,19 +190,19 @@ func NewFromWriters(domain string, level Level, w, e io.WriteCloser) (l *Logger, // NewFile returns a new logger that opens the files for writing. If // multiplex is true, output will be multiplexed to standard output // and standard error as well. -func NewFromFile(domain string, level Level, outFile, errFile string, multiplex bool) (*Logger, error) { +func NewFromFile(domain string, level Level, outFile, errFile string, multiplex bool, flags int) (*Logger, error) { l := &Logger{ domain: domain, level: level, lock: new(sync.Mutex), } - outf, err := os.OpenFile(outFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + outf, err := os.OpenFile(outFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY|flags, 0644) if err != nil { return nil, err } - errf, err := os.OpenFile(errFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + errf, err := os.OpenFile(errFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY|flags, 0644) if err != nil { return nil, err }