142 lines
3 KiB
Go
142 lines
3 KiB
Go
//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
|
||
//
|
||
|
||
var _ Backend = &SyslogBackend{}
|
||
|
||
// 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)
|
||
}
|
||
|
||
if err != nil {
|
||
return fmt.Errorf("cannot log to syslog: %w", err)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// 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
|
||
}
|