// Package logging provides a multi-backend leveled logging facility. /* Backends package logging defines the following builtin backends: * NoopBackend, which discards all messages * FileBackend, which redirects logs to an io.Writer object. It has constructors for files, stdout and stderr * SyslogBackend, only available in unix-like systems, writes log entryies to a syslog daemon. A backend can safely be used by multiple loggers. It is the caller's responsibility to call Close on backends when they are not used anymore to free their resources. */ package logging import ( "errors" "fmt" "strings" "sync" ) //nolint:gochecknoglobals // designed this way var ( loggers map[string]*Logger lock sync.Mutex errInvalidLogLevel = errors.New("invalid log level") ) // Level is the type of log levels. type Level byte //revive:disable:exported const ( Trace Level = iota Debug Info Notice Warning Error Critical Alert Fatal DefaultLevel = Info ) //revive:enable:exported //nolint:gochecknoglobals // designed this way var levelNames = [...]string{ "TRACE", "DEBUG", "INFO", "NOTICE", "WARNING", "ERROR", "CRITICAL", "ALERT", "FATAL", } // Name returns the name of the log level. func (l Level) Name() string { return levelNames[l] } // LevelByName creates a log level given its name. It returns an error if the // name does not match any level. func LevelByName(l string) (Level, error) { for pos, name := range levelNames { if name == l { return Level(pos), nil } } return Debug, fmt.Errorf("unknown log level %q: %w", l, errInvalidLogLevel) } // Formatter is the types of the functions that can be used to format a log // entry. They take a pointer to a record and return a formatted string. type Formatter func(*Record) string // GetLogger returns a logger given its name. if the logger does not exist, it // initializes one with the defaults (it logs to stdout with level INFO). func GetLogger(name string) *Logger { lock.Lock() defer lock.Unlock() if name == "" { name = "default" } l, ok := loggers[name] if !ok { l = NewLogger(name) backend := NewStdoutBackend() l.AddBackend(backend) l.SetLevel(DefaultLevel) loggers[name] = l } return l } func defaultFormatter(r *Record) string { return fmt.Sprintf("%s [%-8s] %s: %s\n", r.Timestamp.Format("2006/01/02 15:04:05"), r.Level.Name(), r.Logger, strings.TrimSpace(r.Message)) } func basicFormatter(r *Record) string { return fmt.Sprintf("%s: %s", r.Logger, strings.TrimSpace(r.Message)) } //nolint:gochecknoinits // init is used by design func init() { loggers = map[string]*Logger{} logger := NewLogger("default") backend := NewStdoutBackend() logger.AddBackend(backend) logger.SetLevel(DefaultLevel) loggers["default"] = logger }