aboutsummaryrefslogblamecommitdiffstats
path: root/ethlog/loggers.go
blob: e656ffbe59b30155a65b2d9fae5af085dedaaf87 (plain) (tree)


















































































































































































                                                                                                  
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}
}