//go:build !windows && !nacl && !plan9 // +build !windows,!nacl,!plan9 package logging import ( "errors" "fmt" "log/syslog" "strings" ) var errUnknownFacility = errors.New("unknown facility") // // Syslog Backend // // SyslogBackend writes the logs to a syslog system. type SyslogBackend struct { w *syslog.Writer formatter Formatter level Level } // NewSyslogBackend initializes a new connection to a syslog server with the // given facility. // tag can contain an identifier for the log stream. It defaults to os.Arg[0]. func NewSyslogBackend(facilityName, tag string) (*SyslogBackend, error) { f, err := facility(facilityName) if err != nil { return nil, err } w, err := syslog.New(f, tag) if err != nil { return nil, fmt.Errorf("cannot initialize syslog: %w", err) } sb := &SyslogBackend{ w: w, formatter: basicFormatter, } return sb, nil } // Write sends an entry to the syslog server. func (sb *SyslogBackend) Write(r *Record) error { var err error text := sb.formatter(r) switch r.Level { case Trace, Debug: err = sb.w.Debug(text) case Info: err = sb.w.Info(text) case Notice: err = sb.w.Notice(text) case Warning: err = sb.w.Warning(text) case Error: err = sb.w.Err(text) case Critical: err = sb.w.Crit(text) case Alert: err = sb.w.Alert(text) case Fatal: err = sb.w.Emerg(text) } return fmt.Errorf("cannot log to syslog: %w", err) } // SetFormatter defines the formatter for this backend. func (sb *SyslogBackend) SetFormatter(f Formatter) { sb.formatter = f } // SetLevel changes the log level of the backend. func (sb *SyslogBackend) SetLevel(level Level) { sb.level = level } // Level returns the log level set for this backend. func (sb *SyslogBackend) Level() Level { return sb.level } // Reopen is a no-op. func (*SyslogBackend) Reopen() error { return nil } // Close closes the connection to the syslog daemon. func (sb *SyslogBackend) Close() error { if err := sb.w.Close(); err != nil { return fmt.Errorf("cannot close syslog: %w", err) } return nil } //nolint:gochecknoglobals // global var is used by design var facilities = map[string]syslog.Priority{ "kern": syslog.LOG_KERN, "user": syslog.LOG_USER, "mail": syslog.LOG_MAIL, "daemon": syslog.LOG_DAEMON, "auth": syslog.LOG_AUTH, "syslog": syslog.LOG_SYSLOG, "lpr": syslog.LOG_LPR, "news": syslog.LOG_NEWS, "uucp": syslog.LOG_UUCP, "cron": syslog.LOG_CRON, "authpriv": syslog.LOG_AUTHPRIV, "ftp": syslog.LOG_FTP, "local0": syslog.LOG_LOCAL0, "local1": syslog.LOG_LOCAL1, "local2": syslog.LOG_LOCAL2, "local3": syslog.LOG_LOCAL3, "local4": syslog.LOG_LOCAL4, "local5": syslog.LOG_LOCAL5, "local6": syslog.LOG_LOCAL6, "local7": syslog.LOG_LOCAL7, } func facility(name string) (syslog.Priority, error) { p, ok := facilities[strings.ToLower(name)] if !ok { return 0, fmt.Errorf("facility '%s' does not exist: %w", name, errUnknownFacility) } return p, nil }