diff options
author | zelig <viktor.tron@gmail.com> | 2014-06-23 19:49:04 +0800 |
---|---|---|
committer | zelig <viktor.tron@gmail.com> | 2014-06-23 19:49:04 +0800 |
commit | 8e9cc3697944c3e568186a5c23ac729f6eb4a1f4 (patch) | |
tree | 96f3b55f7496a2889e0efa302fb03dfd81d5592c /ethlog/loggers.go | |
parent | 0251fae5ccf6984c558d59cd2b36ef89116c061e (diff) | |
download | dexon-8e9cc3697944c3e568186a5c23ac729f6eb4a1f4.tar dexon-8e9cc3697944c3e568186a5c23ac729f6eb4a1f4.tar.gz dexon-8e9cc3697944c3e568186a5c23ac729f6eb4a1f4.tar.bz2 dexon-8e9cc3697944c3e568186a5c23ac729f6eb4a1f4.tar.lz dexon-8e9cc3697944c3e568186a5c23ac729f6eb4a1f4.tar.xz dexon-8e9cc3697944c3e568186a5c23ac729f6eb4a1f4.tar.zst dexon-8e9cc3697944c3e568186a5c23ac729f6eb4a1f4.zip |
refactor logging. Details:
- packages use tagged logger sending log messages to shared (process-wide) logging engine
- log writers (interface ethlog.LogSystem) can be added to the logging engine by wrappers/guis/clients
- shared logging engine dispatching to multiple log systems
- log level can be set separately per log system
- async logging thread: logging IO does not block main thread
- log messages are synchronously stringified to avoid incorrectly logging of changed states
- README.md
- loggers_test
Diffstat (limited to 'ethlog/loggers.go')
-rw-r--r-- | ethlog/loggers.go | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/ethlog/loggers.go b/ethlog/loggers.go new file mode 100644 index 000000000..e656ffbe5 --- /dev/null +++ b/ethlog/loggers.go @@ -0,0 +1,179 @@ +package ethlog + +import ( + "fmt" + "sync" + "log" + "io" + "os" +) + +type LogSystem interface { + GetLogLevel() LogLevel + SetLogLevel(i LogLevel) + Println(v ...interface{}) + Printf(format string, v ...interface{}) +} + +type logMessage struct { + LogLevel LogLevel + format bool + msg string +} + +func newPrintlnLogMessage(level LogLevel, tag string, v...interface{}) *logMessage { + return &logMessage{level, false, fmt.Sprintf("[%s] %s", tag, fmt.Sprint(v...))} +} + +func newPrintfLogMessage(level LogLevel, tag string, format string, v...interface{}) *logMessage { + return &logMessage{level, true, fmt.Sprintf("[%s] %s", tag, fmt.Sprintf(format, v...))} +} + +func (msg *logMessage) send(logger LogSystem) { + if msg.format { + logger.Printf(msg.msg) + } else { + logger.Println(msg.msg) + } +} + +var logMessages chan(*logMessage) +var logSystems []LogSystem +var drained = true + +type LogLevel uint8 + +const ( + Silence LogLevel = iota + ErrorLevel + WarnLevel + InfoLevel + DebugLevel +) + +// log messages are dispatched to log writers +func start() { + for { + select { + case msg := <- logMessages: + for _, logSystem := range logSystems { + if logSystem.GetLogLevel() >= msg.LogLevel { + msg.send(logSystem) + } + } + default: + drained = true + } + } +} + +// waits until log messages are drained (dispatched to log writers) +func Flush() { + for !drained {} +} + +type Logger struct { + tag string +} + +func NewLogger(tag string) *Logger { + return &Logger{tag} +} + +func AddLogSystem(logSystem LogSystem) { + var mutex = &sync.Mutex{} + mutex.Lock() + defer mutex.Unlock() + if logSystems == nil { + logMessages = make(chan *logMessage) + go start() + } + logSystems = append(logSystems, logSystem) +} + +func (logger *Logger) sendln(level LogLevel, v...interface{}) { + if logMessages != nil { + msg := newPrintlnLogMessage(level, logger.tag, v...) + drained = false + logMessages <- msg + } +} + +func (logger *Logger) sendf(level LogLevel, format string, v...interface{}) { + if logMessages != nil { + msg := newPrintfLogMessage(level, logger.tag, format, v...) + drained = false + logMessages <- msg + } +} + +func (logger *Logger) Errorln(v...interface{}) { + logger.sendln(ErrorLevel, v...) +} + +func (logger *Logger) Warnln(v...interface{}) { + logger.sendln(WarnLevel, v...) +} + +func (logger *Logger) Infoln(v...interface{}) { + logger.sendln(InfoLevel, v...) +} + +func (logger *Logger) Debugln(v...interface{}) { + logger.sendln(DebugLevel, v...) +} + +func (logger *Logger) Errorf(format string, v...interface{}) { + logger.sendf(ErrorLevel, format, v...) +} + +func (logger *Logger) Warnf(format string, v...interface{}) { + logger.sendf(WarnLevel, format, v...) +} + +func (logger *Logger) Infof(format string, v...interface{}) { + logger.sendf(InfoLevel, format, v...) +} + +func (logger *Logger) Debugf(format string, v...interface{}) { + logger.sendf(DebugLevel, format, v...) +} + +func (logger *Logger) Fatalln (v...interface{}) { + logger.sendln(ErrorLevel, v...) + Flush() + os.Exit(0) +} + +func (logger *Logger) Fatalf (format string, v...interface{}) { + logger.sendf(ErrorLevel, format, v...) + Flush() + os.Exit(0) +} + +type StdLogSystem struct { + logger *log.Logger + level LogLevel +} + +func (t *StdLogSystem) Println(v ...interface{}) { + t.logger.Println(v...) +} + +func (t *StdLogSystem) Printf(format string, v ...interface{}) { + t.logger.Printf(format, v...) +} + +func (t *StdLogSystem) SetLogLevel(i LogLevel) { + t.level = i +} + +func (t *StdLogSystem) GetLogLevel() LogLevel { + return t.level +} + +func NewStdLogSystem(writer io.Writer, flags int, level LogLevel) *StdLogSystem { + logger := log.New(writer, "", flags) + return &StdLogSystem{logger, level} +} + |