Better domain handling in logging.

This commit is contained in:
Kyle Isom 2015-09-22 13:26:06 -07:00
parent 4b3f1037b3
commit ea689c7e97
3 changed files with 102 additions and 29 deletions

View File

@ -3,7 +3,7 @@ package logging_test
import "github.com/kisom/goutils/logging" import "github.com/kisom/goutils/logging"
var log = logging.Init() var log = logging.Init()
var olog = logging.New("subsystem #42", logging.LevelNotice) var olog, _ = logging.New("subsystem #42", logging.LevelNotice)
func Example() { func Example() {
log.Notice("Hello, world.") log.Notice("Hello, world.")

View File

@ -64,7 +64,7 @@ var levelPrefix = [...]string{
var DateFormat = "2006-01-02T15:03:04-0700" var DateFormat = "2006-01-02T15:03:04-0700"
func (l *Logger) outputf(level Level, format string, v []interface{}) { func (l *Logger) outputf(level Level, format string, v []interface{}) {
if !logConfig.registered[l.domain] { if !l.Enabled() {
return return
} }
@ -81,7 +81,7 @@ func (l *Logger) outputf(level Level, format string, v []interface{}) {
} }
func (l *Logger) output(level Level, v []interface{}) { func (l *Logger) output(level Level, v []interface{}) {
if !logConfig.registered[l.domain] { if !l.Enabled() {
return return
} }

View File

@ -9,16 +9,17 @@ import (
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"sync" "sync"
"github.com/kisom/goutils/mwc" "github.com/kisom/goutils/mwc"
) )
var logConfig = struct { var logConfig = struct {
registered map[string]bool registered map[string]*Logger
lock *sync.Mutex lock *sync.Mutex
}{ }{
registered: map[string]bool{}, registered: map[string]*Logger{},
lock: new(sync.Mutex), lock: new(sync.Mutex),
} }
@ -28,16 +29,19 @@ const DefaultLevel = LevelNotice
// Init returns a new default logger. The domain is set to the // Init returns a new default logger. The domain is set to the
// program's name, and the default logging level is used. // program's name, and the default logging level is used.
func Init() *Logger { func Init() *Logger {
return New(filepath.Base(os.Args[0]), DefaultLevel) l, _ := New(filepath.Base(os.Args[0]), DefaultLevel)
return l
} }
// A Logger writes logs on behalf of a particular domain at a certain // A Logger writes logs on behalf of a particular domain at a certain
// level. // level.
type Logger struct { type Logger struct {
domain string enabled bool
level Level lock *sync.Mutex
out io.WriteCloser domain string
err io.WriteCloser level Level
out io.WriteCloser
err io.WriteCloser
} }
// Close closes the log's writers and suppresses the logger. // Close closes the log's writers and suppresses the logger.
@ -55,15 +59,30 @@ func (l *Logger) Close() error {
func Suppress(domain string) { func Suppress(domain string) {
logConfig.lock.Lock() logConfig.lock.Lock()
defer logConfig.lock.Unlock() defer logConfig.lock.Unlock()
logConfig.registered[domain] = false l, ok := logConfig.registered[domain]
if ok {
l.Suppress()
}
}
// SuppressPrefix suppress logs whose domain is prefixed with the
// prefix.
func SuppressPrefix(prefix string) {
logConfig.lock.Lock()
defer logConfig.lock.Unlock()
for domain, l := range logConfig.registered {
if strings.HasPrefix(domain, prefix) {
l.Suppress()
}
}
} }
// SuppressAll suppresses all logging output. // SuppressAll suppresses all logging output.
func SuppressAll() { func SuppressAll() {
logConfig.lock.Lock() logConfig.lock.Lock()
defer logConfig.lock.Unlock() defer logConfig.lock.Unlock()
for domain := range logConfig.registered { for _, l := range logConfig.registered {
logConfig.registered[domain] = false l.Suppress()
} }
} }
@ -71,48 +90,90 @@ func SuppressAll() {
func Enable(domain string) { func Enable(domain string) {
logConfig.lock.Lock() logConfig.lock.Lock()
defer logConfig.lock.Unlock() defer logConfig.lock.Unlock()
logConfig.registered[domain] = true l, ok := logConfig.registered[domain]
if ok {
l.Enable()
}
}
// EnablePrefix enables logs whose domain is prefixed with prefix.
func EnablePrefix(prefix string) {
logConfig.lock.Lock()
defer logConfig.lock.Unlock()
for domain, l := range logConfig.registered {
if strings.HasPrefix(domain, prefix) {
l.Enable()
}
}
} }
// EnableAll enables all domains. // EnableAll enables all domains.
func EnableAll() { func EnableAll() {
logConfig.lock.Lock() logConfig.lock.Lock()
defer logConfig.lock.Unlock() defer logConfig.lock.Unlock()
for domain := range logConfig.registered { for _, l := range logConfig.registered {
logConfig.registered[domain] = true l.Enable()
} }
} }
// New returns a new logger that writes to standard output for Notice // New returns a new logger that writes to standard output for Notice
// and below and standard error for levels above Notice. // and below and standard error for levels above Notice. If a logger
func New(domain string, level Level) *Logger { // with the same domain exists, the logger will set its level to level
l := &Logger{ // and return the logger; in this case, the registered return value
// will be true.
func New(domain string, level Level) (l *Logger, registered bool) {
logConfig.lock.Lock()
defer logConfig.lock.Unlock()
l = logConfig.registered[domain]
if l != nil {
l.SetLevel(level)
return l, true
}
l = &Logger{
domain: domain, domain: domain,
level: level, level: level,
out: os.Stdout, out: os.Stdout,
err: os.Stderr, err: os.Stderr,
lock: new(sync.Mutex),
} }
Enable(domain) l.Enable()
return l logConfig.registered[domain] = l
return l, false
} }
// NewWriters returns a new logger that writes to the w io.WriteCloser for // NewWriters returns a new logger that writes to the w io.WriteCloser
// Notice and below and to the e io.WriteCloser for levels above Notice. If e is nil, w will be used. // for Notice and below and to the e io.WriteCloser for levels above
func NewFromWriters(domain string, level Level, w, e io.WriteCloser) *Logger { // Notice. If e is nil, w will be used. If a logger with the same
// domain exists, the logger will set its level to level and return
// the logger; in this case, the registered return value will be true.
func NewFromWriters(domain string, level Level, w, e io.WriteCloser) (l *Logger, registered bool) {
logConfig.lock.Lock()
defer logConfig.lock.Unlock()
l = logConfig.registered[domain]
if l != nil {
l.SetLevel(level)
return l, true
}
if e == nil { if e == nil {
e = w e = w
} }
l := &Logger{ l = &Logger{
domain: domain, domain: domain,
level: level, level: level,
out: w, out: w,
err: e, err: e,
lock: new(sync.Mutex),
} }
Enable(domain) l.Enable()
return l logConfig.registered[domain] = l
return l, false
} }
// NewFile returns a new logger that opens the files for writing. If // NewFile returns a new logger that opens the files for writing. If
@ -122,6 +183,7 @@ func NewFromFile(domain string, level Level, outFile, errFile string, multiplex
l := &Logger{ l := &Logger{
domain: domain, domain: domain,
level: level, 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, 0644)
@ -148,12 +210,21 @@ func NewFromFile(domain string, level Level, outFile, errFile string, multiplex
// Enable allows output from the logger. // Enable allows output from the logger.
func (l *Logger) Enable() { func (l *Logger) Enable() {
Enable(l.domain) l.lock.Lock()
defer l.lock.Unlock()
l.enabled = true
}
// Enabled returns true if the logger is enabled.
func (l *Logger) Enabled() bool {
return l.enabled
} }
// Suppress ignores output from the logger. // Suppress ignores output from the logger.
func (l *Logger) Suppress() { func (l *Logger) Suppress() {
Suppress(l.domain) l.lock.Lock()
defer l.lock.Unlock()
l.enabled = false
} }
// Domain returns the domain of the logger. // Domain returns the domain of the logger.
@ -163,5 +234,7 @@ func (l *Logger) Domain() string {
// SetLevel changes the level of the logger. // SetLevel changes the level of the logger.
func (l *Logger) SetLevel(level Level) { func (l *Logger) SetLevel(level Level) {
l.lock.Lock()
defer l.lock.Unlock()
l.level = level l.level = level
} }