diff --git a/README.md b/README.md index 25f4cc7..bb8ad29 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ Contents: rand/ Utilities for working with math/rand. sbuf/ A byte buffer that can be wiped. seekbuf/ A read-seekable byte buffer. + syslog/ Syslog-type logging. tee/ Emulate tee(1)'s functionality in io.Writers. testio/ Various I/O utilities useful during testing. testutil/ Various utility functions useful during testing. diff --git a/syslog/BUILD.bazel b/syslog/BUILD.bazel new file mode 100644 index 0000000..a73a852 --- /dev/null +++ b/syslog/BUILD.bazel @@ -0,0 +1,9 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "log", + srcs = ["logger.go"], + importpath = "git.wntrmute.dev/kyle/kdhcp/log", + visibility = ["//visibility:public"], + deps = ["@com_github_hashicorp_go_syslog//:go-syslog"], +) diff --git a/syslog/logger.go b/syslog/logger.go new file mode 100644 index 0000000..8677f85 --- /dev/null +++ b/syslog/logger.go @@ -0,0 +1,257 @@ +// syslog is a syslog-type facility for logging. +package syslog + +import ( + "fmt" + "os" + "strings" + "time" + + gsyslog "github.com/hashicorp/go-syslog" +) + +type logger struct { + l gsyslog.Syslogger + p gsyslog.Priority +} + +func (log *logger) printf(p gsyslog.Priority, format string, args ...interface{}) { + if !strings.HasSuffix(format, "\n") { + format += "\n" + } + + if p <= log.p { + fmt.Printf("%s [%s] ", prioritiev[p], timestamp()) + fmt.Printf(format, args...) + } + + if log.l != nil { + log.l.WriteLevel(p, []byte(fmt.Sprintf(format, args...))) + } +} + +func (log *logger) print(p gsyslog.Priority, args ...interface{}) { + if p <= log.p { + fmt.Printf("%s [%s] ", prioritiev[p], timestamp()) + fmt.Print(args...) + } + + if log.l != nil { + log.l.WriteLevel(p, []byte(fmt.Sprint(args...))) + } +} + +func (log *logger) println(p gsyslog.Priority, args ...interface{}) { + if p <= log.p { + fmt.Printf("%s [%s] ", prioritiev[p], timestamp()) + fmt.Println(args...) + } + + if log.l != nil { + log.l.WriteLevel(p, []byte(fmt.Sprintln(args...))) + } +} + +func (log *logger) adjustPriority(level string) error { + priority, ok := priorities[level] + if !ok { + return fmt.Errorf("log: unknown priority %s", level) + } + + log.p = priority + return nil +} + +var log = &logger{p: gsyslog.LOG_WARNING} + +var priorities = map[string]gsyslog.Priority{ + "EMERG": gsyslog.LOG_EMERG, + "ALERT": gsyslog.LOG_ALERT, + "CRIT": gsyslog.LOG_CRIT, + "ERR": gsyslog.LOG_ERR, + "WARNING": gsyslog.LOG_WARNING, + "NOTICE": gsyslog.LOG_NOTICE, + "INFO": gsyslog.LOG_INFO, + "DEBUG": gsyslog.LOG_DEBUG, +} + +var prioritiev = map[gsyslog.Priority]string{ + gsyslog.LOG_EMERG: "EMERG", + gsyslog.LOG_ALERT: "ALERT", + gsyslog.LOG_CRIT: "CRIT", + gsyslog.LOG_ERR: "ERR", + gsyslog.LOG_WARNING: "WARNING", + gsyslog.LOG_NOTICE: "NOTICE", + gsyslog.LOG_INFO: "INFO", + gsyslog.LOG_DEBUG: "DEBUG", +} + +func timestamp() string { + return time.Now().Format("2006-01-02 15:04:05 MST") +} + +type Options struct { + Level string + Tag string + Facility string + WriteSyslog bool +} + +// DefaultOptions returns a sane set of defaults for syslog, using the program +// name as the tag name. withSyslog controls whether logs should be sent to +// syslog, too. +func DefaultOptions(tag string, withSyslog bool) { + if tag == "" { + tag = os.Args[0] + } + + return &DefaultOptions{ + Level: "WARNING", + Tag: tag, + Facility: "daemon", + WriteSyslog: withSyslog, + } +} + +// DefaultDefaultOptions returns a sane set of debug defaults for syslog, +// using the program name as the tag name. withSyslog controls whether logs +// should be sent to syslog, too. +func DefaultDebugOptions(tag string, withSyslog bool) { + if tag == "" { + tag = os.Args[0] + } + + return &DefaultOptions{ + Level: "DEBUG", + Facility: "daemon", + WriteSyslog: withSyslog, + } +} + +func Setup(opts *Options) error { + priority, ok := priorities[opts.Level] + if !ok { + return fmt.Errorf("log: unknown priority %s", level) + } + + log.p = priority + + var err error + log.l, err = gsyslog.NewLogger(priority, opts.Facility, opts.Tag) + if err != nil { + return err + } + + return nil +} + +func Debug(args ...interface{}) { + log.print(gsyslog.LOG_DEBUG, args...) +} + +func Info(args ...interface{}) { + log.print(gsyslog.LOG_INFO, args...) +} + +func Notice(args ...interface{}) { + log.print(gsyslog.LOG_NOTICE, args...) +} + +func Warning(args ...interface{}) { + log.print(gsyslog.LOG_WARNING, args...) +} + +func Err(args ...interface{}) { + log.print(gsyslog.LOG_ERR, args...) +} + +func Crit(args ...interface{}) { + log.print(gsyslog.LOG_CRIT, args...) +} + +func Alert(args ...interface{}) { + log.print(gsyslog.LOG_ALERT, args...) +} + +func Emerg(args ...interface{}) { + log.print(gsyslog.LOG_EMERG, args...) +} + +func Debugln(args ...interface{}) { + log.println(gsyslog.LOG_DEBUG, args...) +} + +func Infoln(args ...interface{}) { + log.println(gsyslog.LOG_INFO, args...) +} + +func Noticeln(args ...interface{}) { + log.println(gsyslog.LOG_NOTICE, args...) +} + +func Warningln(args ...interface{}) { + log.print(gsyslog.LOG_WARNING, args...) +} + +func Errln(args ...interface{}) { + log.println(gsyslog.LOG_ERR, args...) +} + +func Critln(args ...interface{}) { + log.println(gsyslog.LOG_CRIT, args...) +} + +func Alertln(args ...interface{}) { + log.println(gsyslog.LOG_ALERT, args...) +} + +func Emergln(args ...interface{}) { + log.println(gsyslog.LOG_EMERG, args...) +} + +func Debugf(format string, args ...interface{}) { + log.printf(gsyslog.LOG_DEBUG, format, args...) +} + +func Infof(format string, args ...interface{}) { + log.printf(gsyslog.LOG_INFO, format, args...) +} + +func Noticef(format string, args ...interface{}) { + log.printf(gsyslog.LOG_NOTICE, format, args...) +} + +func Warningf(format string, args ...interface{}) { + log.printf(gsyslog.LOG_WARNING, format, args...) +} + +func Errf(format string, args ...interface{}) { + log.printf(gsyslog.LOG_ERR, format, args...) +} + +func Critf(format string, args ...interface{}) { + log.printf(gsyslog.LOG_CRIT, format, args...) +} + +func Alertf(format string, args ...interface{}) { + log.printf(gsyslog.LOG_ALERT, format, args...) +} + +func Emergf(format string, args ...interface{}) { + log.printf(gsyslog.LOG_EMERG, format, args...) + os.Exit(1) +} + +func Fatal(args ...interface{}) { + log.println(gsyslog.LOG_ERR, args...) + os.Exit(1) +} + +func Fatalf(format string, args ...interface{}) { + log.printf(gsyslog.LOG_ERR, format, args...) + os.Exit(1) +} + +func ChangePriority(level string) error { + return log.adjustPriority(level) +}