package logging import ( "fmt" "log" "os" "sync" ) const exitCodeFatal = 100 // 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 { mutex sync.Mutex name string backends []Backend } // NewLogger initializes a new Logger with no backend and with the default log level. func NewLogger(name string) *Logger { l := &Logger{ name: name, } return l } // AddBackend add a new Backend to the logger. All set backends are kept. func (l *Logger) AddBackend(b Backend) { l.mutex.Lock() defer l.mutex.Unlock() l.backends = append(l.backends, b) } // SetBackend sets the backend list to the logger. Any existing backend will be lost. func (l *Logger) SetBackend(b ...Backend) { l.mutex.Lock() defer l.mutex.Unlock() 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 { logger *Logger level Level } func (b *buffer) Write(p []byte) (int, 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.mutex.Lock() defer l.mutex.Unlock() r := NewRecord(l.name, level, m) for _, backend := range l.backends { if r.Level >= backend.Level() { if err := backend.Write(r); err != nil { //revive:disable-next-line:unhandled-error stop error handling recursion! fmt.Fprintf(os.Stderr, "Cannot write logs: %v", err) } } } } // Trace logs a message with the Trace level. func (l *Logger) Trace(text string) { l.Log(Trace, text) } // Tracef formats the message with given args and logs the result with the // Trace level. func (l *Logger) Tracef(text string, args ...interface{}) { l.Trace(fmt.Sprintf(text, args...)) } // 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...)) } // Notice logs a message with the Notice level. func (l *Logger) Notice(text string) { l.Log(Notice, text) } // Noticef formats the message with given args and logs the result with the // Notice level. func (l *Logger) Noticef(text string, args ...interface{}) { l.Notice(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...)) } // Alert logs a message with the Alert level. func (l *Logger) Alert(text string) { l.Log(Alert, text) } // Alertf formats the message with given args and logs the result with the. // Alert level. func (l *Logger) Alertf(text string, args ...interface{}) { l.Alert(fmt.Sprintf(text, args...)) } // Fatal logs a message with the Fatal level. func (l *Logger) Fatal(text string) { l.Log(Debug, text) os.Exit(exitCodeFatal) //nolint:revive // This is wanted if fatal is called } // 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...)) }