package logging import ( "fmt" "log" "os" "sync" ) // Logger is a facility that writes logs to one or more backands (files, // stdout/stderr, syslog, etc.) which can be configured independently // // Loggers are concurrent-safe. type Logger struct { sync.Mutex name string backends []Backend } // NewLogger initializes a new Logger with no backend and with the default log level. func NewLogger(name string) (l *Logger) { l = &Logger{ name: name, } return } // AddBackend add a new Backend to the logger. All set backends are kept. func (l *Logger) AddBackend(b Backend) { l.backends = append(l.backends, b) } // SetBackend sets the backend list to the logger. Any existing backend will be lost. // FIXME must close file backends to avoid fd leaks func (l *Logger) SetBackend(b ...Backend) { l.backends = b } // SetLevel changes the log level of all regisered backends to the given level. func (l *Logger) SetLevel(level Level) { for _, backend := range l.backends { backend.SetLevel(level) } } type buffer struct { level Level logger *Logger } func (b *buffer) Write(p []byte) (n int, err error) { b.logger.Log(b.level, string(p)) return len(p), nil } // AsStdLog encapsulate the logger in an instance of lof.Logger from the // standard library and returns it. // // It is there for interoperability reasons. func (l *Logger) AsStdLog(level Level) *log.Logger { stdLogger := log.New(&buffer{logger: l, level: level}, "", 0) return stdLogger } // Log sends a record containing the message `m` to the registered backends // whose level is at least `level` func (l *Logger) Log(level Level, m string) { l.Lock() defer l.Unlock() r := NewRecord(l.name, level, m) for _, backend := range l.backends { if r.Level >= backend.Level() { _ = backend.Write(r) } } } // Debug logs a message with the Debug level func (l *Logger) Debug(text string) { l.Log(Debug, text) } // Debugf formats the message with given args and logs the result with the // Debug level func (l *Logger) Debugf(text string, args ...interface{}) { l.Debug(fmt.Sprintf(text, args...)) } // Info logs a message with the Info level func (l *Logger) Info(text string) { l.Log(Info, text) } // Infof formats the message with given args and logs the result with the // Info level func (l *Logger) Infof(text string, args ...interface{}) { l.Info(fmt.Sprintf(text, args...)) } // Warning logs a message with the Warning level func (l *Logger) Warning(text string) { l.Log(Warning, text) } // Warningf formats the message with given args and logs the result with the // Warning level func (l *Logger) Warningf(text string, args ...interface{}) { l.Warning(fmt.Sprintf(text, args...)) } // Error logs a message with the Error level func (l *Logger) Error(text string) { l.Log(Error, text) } // Errorf formats the message with given args and logs the result with the // Error level func (l *Logger) Errorf(text string, args ...interface{}) { l.Error(fmt.Sprintf(text, args...)) } // Critical logs a message with the Critical level func (l *Logger) Critical(text string) { l.Log(Critical, text) } // Criticalf formats the message with given args and logs the result with the // Critical level func (l *Logger) Criticalf(text string, args ...interface{}) { l.Critical(fmt.Sprintf(text, args...)) } // Fatal logs a message with the Fatal level func (l *Logger) Fatal(text string) { l.Log(Debug, text) os.Exit(100) } // Fatalf formats the message with given args and logs the result with the // Fatal level func (l *Logger) Fatalf(text string, args ...interface{}) { l.Fatal(fmt.Sprintf(text, args...)) }