package logging import ( "errors" "fmt" "io" "log/syslog" "os" "strings" ) type Backend interface { Write(*Record) error SetFormatter(*Formatter) SetLevel(Level) Level() Level } // // Backend to write in file-like objects // type FileBackend struct { l io.Writer formatter *Formatter level Level } // Creates a new backend to write the logs on the standard output func NewStdoutBackend() (b *FileBackend) { b = &FileBackend{ l: os.Stdout, formatter: &defaultFormatter, } return } // Creates a new backend to write the logs on the error output func NewStderrBackend() (b *FileBackend) { b = &FileBackend{ l: os.Stderr, formatter: &defaultFormatter, } return } // Creates a new backend to write the logs in a given file func NewFileBackend(filename string) (b *FileBackend, e error) { filename_fd, err := os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644) if err != nil { e = errors.New(fmt.Sprintf("Cannot open log file %s (%s)", filename, err.Error())) } b = &FileBackend{ l: filename_fd, formatter: &defaultFormatter, } return } // Creates a new backend to write the logs in a given io.Writer func NewIoBackend(buf io.Writer) (b *FileBackend) { return &FileBackend{ l: buf, formatter: &defaultFormatter, } } func (b FileBackend) Write(r *Record) error { text := (*b.formatter)(r) _, err := io.WriteString(b.l, text) return err } func (b *FileBackend) SetLevel(l Level) { b.level = l } func (b *FileBackend) Level() Level { return b.level } func (b *FileBackend) SetFormatter(f *Formatter) { b.formatter = f } // // Syslog Backend // type SyslogBackend struct { w *syslog.Writer formatter *Formatter level Level } func NewSyslogBackend(facilityName string, tag string) (Backend, error) { f, err := facility(facilityName) if err != nil { return nil, err } w, err := syslog.New(f, tag) if err != nil { return nil, err } sb := &SyslogBackend{ w: w, formatter: &basicFormatter, } return sb, nil } func (sb *SyslogBackend) Write(r *Record) (err error) { text := (*sb.formatter)(r) switch r.Level { case DEBUG: err = sb.w.Debug(text) case INFO: err = sb.w.Info(text) case WARNING: err = sb.w.Warning(text) case ERROR: err = sb.w.Err(text) case CRITICAL: err = sb.w.Crit(text) case FATAL: err = sb.w.Emerg(text) } return err } func (sb *SyslogBackend) SetFormatter(f *Formatter) { sb.formatter = f } func (sb *SyslogBackend) SetLevel(level Level) { sb.level = level } func (sb *SyslogBackend) Level() Level { return sb.level } 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) { if p, ok := facilities[strings.ToLower(name)]; !ok { return 0, fmt.Errorf("Facility '%s' does not exist", name) } else { return p, nil } }