pax_global_header00006660000000000000000000000064126761301670014523gustar00rootroot0000000000000052 comment=197ef798aed28e08ed3e176e678fda81be993a31 xlog-1.0.0/000077500000000000000000000000001267613016700124725ustar00rootroot00000000000000xlog-1.0.0/README.md000066400000000000000000000045411267613016700137550ustar00rootroot00000000000000# xlog [![GoDoc](https://godoc.org/github.com/hlandau/xlog?status.svg)](https://godoc.org/github.com/hlandau/xlog) Yet another logging package for Go. The main thing about this package is that it's good for usage in libraries and doesn't involve itself with policy. Essentially, if, as a library, you want to log something, you write this: ```go var log, Log = xlog.NewQuiet("my.logger.name") func Foo() { log.Debugf("Bar") } ``` The `log` variable is what you use to log, and the `Log` variable is exported from the package and provides methods for controlling the log site. (These are actually two interfaces to the same object which enforce this pattern.) The idea is that consuming code can call somepkg.Log to control where it logs to, at what verbosity, etc. You should instantiate with `NewQuiet` if you are a library, as this suppresses most log messages by default. Loggers created with `New` don't suppress any log messages by default. xlog uses a traditional Print/Printf interface. It also has the following conveniences: - Methods ending in `e`, such as `Debuge`, take an error as their first argument and are no-ops if it is nil. - `Fatal` and `Panic` call os.Exit(1) and Panic, respectively. The `e` variants of these are no-ops if the error is nil, providing a simple assertion mechanism. xlog uses syslog severities (Emergency, Alert, Critical, Error, Warning, Notice, Info, Debug) and also provides a Trace severity which is even less severe than Debug. You should generally not emit Alert or Emergency severities from your code, as these are of system-level significance. You can visit all registered log sites in order to configure loggers programmatically. Loggers should be named via a dot-separated hierarchy with names in lowercase. If you have a repository called `foo` and a subpackage `baz`, naming the logger for that subpackage `foo.baz` might be reasonable. Loggers are arranged in a hierarchy terminating in the root logger, which is configured to log to stderr by default. You can create a logger under another logger using `NewUnder`. ## Licence © 2014—2016 Hugo Landau MIT License [Licenced under the licence with SHA256 hash `fd80a26fbb3f644af1fa994134446702932968519797227e07a1368dea80f0bc`, a copy of which can be found here.](https://raw.githubusercontent.com/hlandau/acme/master/_doc/COPYING.MIT) xlog-1.0.0/logger.go000066400000000000000000000136601267613016700143060ustar00rootroot00000000000000package xlog import "os" import "fmt" // Logger is the interface exposed to the internals of a package, which uses it // to log messages. This is the other side of a Site. // // The 'f' functions work like Printf. The suffix-free functions work like // 'Print'. The 'e' functions are no-ops if nil is passed for the error; // otherwise, they print the error as well as the arguments specified. // // Fatal calls os.Exit(1) like "log", and Panic panics. Both emit // Critical-severity log messages before doing so. type Logger struct { Sink } // func (l Logger) Tracef(format string, params ...interface{}) { l.ReceiveLocally(SevTrace, format, params...) } func (l Logger) Debugf(format string, params ...interface{}) { l.ReceiveLocally(SevDebug, format, params...) } func (l Logger) Infof(format string, params ...interface{}) { l.ReceiveLocally(SevInfo, format, params...) } func (l Logger) Noticef(format string, params ...interface{}) { l.ReceiveLocally(SevNotice, format, params...) } func (l Logger) Warnf(format string, params ...interface{}) { l.ReceiveLocally(SevWarn, format, params...) } func (l Logger) Errorf(format string, params ...interface{}) { l.ReceiveLocally(SevError, format, params...) } func (l Logger) Criticalf(format string, params ...interface{}) { l.ReceiveLocally(SevCritical, format, params...) } func (l Logger) Alertf(format string, params ...interface{}) { l.ReceiveLocally(SevAlert, format, params...) } func (l Logger) Emergencyf(format string, params ...interface{}) { l.ReceiveLocally(SevEmergency, format, params...) } func (l Logger) Panicf(format string, params ...interface{}) { l.Criticalf("panic: "+format, params...) panic(fmt.Sprintf(format, params...)) } func (l Logger) Fatalf(format string, params ...interface{}) { l.Criticalf("fatal: "+format, params...) os.Exit(1) } func (l Logger) Traceef(err error, format string, params ...interface{}) { l.ReceiveLocallye(SevTrace, err, format, params...) } func (l Logger) Debugef(err error, format string, params ...interface{}) { l.ReceiveLocallye(SevDebug, err, format, params...) } func (l Logger) Infoef(err error, format string, params ...interface{}) { l.ReceiveLocallye(SevInfo, err, format, params...) } func (l Logger) Noticeef(err error, format string, params ...interface{}) { l.ReceiveLocallye(SevNotice, err, format, params...) } func (l Logger) Warnef(err error, format string, params ...interface{}) { l.ReceiveLocallye(SevWarn, err, format, params...) } func (l Logger) Erroref(err error, format string, params ...interface{}) { l.ReceiveLocallye(SevError, err, format, params...) } func (l Logger) Criticalef(err error, format string, params ...interface{}) { l.ReceiveLocallye(SevCritical, err, format, params...) } func (l Logger) Alertef(err error, format string, params ...interface{}) { l.ReceiveLocallye(SevAlert, err, format, params...) } func (l Logger) Emergencyef(err error, format string, params ...interface{}) { l.ReceiveLocallye(SevEmergency, err, format, params...) } func (l Logger) Panicef(err error, format string, params ...interface{}) { if err != nil { l.Criticalef(err, "panic: "+format, params...) panic(fmt.Sprintf(format, params...)) } } func (l Logger) Fatalef(err error, format string, params ...interface{}) { if err != nil { l.Criticalef(err, "fatal: "+format, params...) os.Exit(1) } } // TODO: optimize this func (l Logger) Trace(params ...interface{}) { l.Tracef("%s", fmt.Sprint(params...)) } func (l Logger) Debug(params ...interface{}) { l.Debugf("%s", fmt.Sprint(params...)) } func (l Logger) Info(params ...interface{}) { l.Infof("%s", fmt.Sprint(params...)) } func (l Logger) Notice(params ...interface{}) { l.Noticef("%s", fmt.Sprint(params...)) } func (l Logger) Warn(params ...interface{}) { l.Warnf("%s", fmt.Sprint(params...)) } func (l Logger) Error(params ...interface{}) { l.Errorf("%s", fmt.Sprint(params...)) } func (l Logger) Critical(params ...interface{}) { l.Criticalf("%s", fmt.Sprint(params...)) } func (l Logger) Alert(params ...interface{}) { l.Alertf("%s", fmt.Sprint(params...)) } func (l Logger) Emergency(params ...interface{}) { l.Emergencyf("%s", fmt.Sprint(params...)) } func (l Logger) Panic(params ...interface{}) { l.Panicf("%s", fmt.Sprint(params...)) } func (l Logger) Fatal(params ...interface{}) { l.Fatalf("%s", fmt.Sprint(params...)) } // func (l Logger) Tracee(err error, params ...interface{}) { if err != nil { l.Tracef("%s: %v", fmt.Sprint(params...), err) } } func (l Logger) Debuge(err error, params ...interface{}) { if err != nil { l.Debugf("%s: %v", fmt.Sprint(params...), err) } } func (l Logger) Infoe(err error, params ...interface{}) { if err != nil { l.Infof("%s: %v", fmt.Sprint(params...), err) } } func (l Logger) Noticee(err error, params ...interface{}) { if err != nil { l.Noticef("%s: %v", fmt.Sprint(params...), err) } } func (l Logger) Warne(err error, params ...interface{}) { if err != nil { l.Warnf("%s: %v", fmt.Sprint(params...), err) } } func (l Logger) Errore(err error, params ...interface{}) { if err != nil { l.Errorf("%s: %v", fmt.Sprint(params...), err) } } func (l Logger) Criticale(err error, params ...interface{}) { if err != nil { l.Criticalf("%s: %v", fmt.Sprint(params...), err) } } func (l Logger) Alerte(err error, params ...interface{}) { if err != nil { l.Alertf("%s: %v", fmt.Sprint(params...), err) } } func (l Logger) Emergencye(err error, params ...interface{}) { if err != nil { l.Emergencyf("%s: %v", fmt.Sprint(params...), err) } } func (l Logger) Fatale(err error, params ...interface{}) { if err != nil { l.Fatalf("%s: %v", fmt.Sprint(params...), err) } } func (l Logger) Panice(err error, params ...interface{}) { if err != nil { l.Panicf("%s: %v", fmt.Sprint(params...), err) } } func (l Logger) ReceiveLocallye(severity Severity, err error, format string, params ...interface{}) { if err == nil { return } l.ReceiveLocally(severity, "%s: %v", fmt.Sprintf(format, params...), err) } xlog-1.0.0/multisink.go000066400000000000000000000020111267613016700150320ustar00rootroot00000000000000package xlog // A sink which dispatches to zero or more other sinks. type MultiSink struct { sinks []Sink } // Add a sink to the MultiSink. Idempotent. func (ms *MultiSink) Add(sink Sink) { for _, s := range ms.sinks { if s == sink { return } } ms.sinks = append(ms.sinks, sink) } // Remove a sink from the MultiSink. Idempotent. func (ms *MultiSink) Remove(sink Sink) { var newSinks []Sink for _, s := range ms.sinks { if s != sink { newSinks = append(newSinks, s) } } ms.sinks = newSinks } // (Implements Sink.) func (ms *MultiSink) ReceiveLocally(sev Severity, format string, params ...interface{}) { for _, s := range ms.sinks { s.ReceiveLocally(sev, format, params...) } } // (Implements Sink.) func (ms *MultiSink) ReceiveFromChild(sev Severity, format string, params ...interface{}) { for _, s := range ms.sinks { s.ReceiveFromChild(sev, format, params...) } } // The null sink. All log messages to this sink will be discarded. var NullSink Sink func init() { NullSink = &MultiSink{} } xlog-1.0.0/severity.go000066400000000000000000000053751267613016700147050ustar00rootroot00000000000000package xlog import "strings" // Log message severity. This is the syslog severity order. // // Note that Emergency and Alert are system-level severities. Generally // speaking, application programs should not emit log messages at such // severities unless they are programs which monitor the system for // system-level issues. i.e., programs should never emit Emergency or Alert // messages regarding issues with their own operation. // // Programs suffering from critical failures should emit log messages at the // Critical severity. The Panic*() and Fatal*() log message functions in this // package emit log messages at the Critical level. // // The Error severity should be used when errors occur which do not constitute // a critical or unrecoverable failure of the program. // // Any severity less severe than Debug is not part of the syslog severity // order. These are converted to messages of Debug severity when exported // to e.g. syslog. // // Trace should be used for extremely verbose debugging information which // is likely to be used mainly for debugging and is of such verbosity that it // may overwhelm a programmer unless enabled only for a few specific // facilities. type Severity int const ( SevEmergency Severity = iota SevAlert SevCritical SevError SevWarn SevNotice SevInfo SevDebug SevTrace SevNone Severity = -1 // (Do not use.) ) var severityString = map[Severity]string{ SevEmergency: "EMERGENCY", // EM EMR EMER SevAlert: "ALERT", // AL ALR ALER SevCritical: "CRITICAL", // CR CRT CRIT SevError: "ERROR", // ER ERR ERRO SevWarn: "WARN", // WA WRN WARN SevNotice: "NOTICE", // NO NOT NOTC SevInfo: "INFO", // IN INF INFO SevDebug: "DEBUG", // DE DBG DEBG SevTrace: "TRACE", // TR TRC TRAC } var ansiSeverityString = map[Severity]string{ SevEmergency: "\x1B[41;37mEMERGENCY\x1B[0m", SevAlert: "\x1B[41;37mALERT\x1B[0m", SevCritical: "\x1B[41;37mCRITICAL\x1B[0m", SevError: "\x1B[31mERROR\x1B[0m", SevWarn: "\x1B[33mWARN\x1B[0m", SevNotice: "NOTICE\x1B[0m", SevInfo: "INFO\x1B[0m", SevDebug: "DEBUG\x1B[0m", SevTrace: "TRACE\x1B[0m", } var severityValue = map[string]Severity{} func init() { for k, v := range severityString { severityValue[v] = k } } // Returns the severity as an uppercase unabbreviated string. func (severity Severity) String() string { return severityString[severity] } // Parse a severity string. func ParseSeverity(severity string) (s Severity, ok bool) { s, ok = severityValue[strings.ToUpper(severity)] return } // Returns the syslog-compatible severity. Converts severities // less severe than Debug to Debug. func (severity Severity) Syslog() Severity { if severity > SevDebug { return SevDebug } return severity } xlog-1.0.0/syslogsink.go000066400000000000000000000024061267613016700152300ustar00rootroot00000000000000package xlog import "fmt" // Interface compatible with "log/syslog".Writer. type Syslogger interface { Alert(m string) error Crit(m string) error Debug(m string) error Emerg(m string) error Err(m string) error Info(m string) error Notice(m string) error Warning(m string) error } // A sink that logs to a "log/syslog".Writer-like interface. type SyslogSink struct { s Syslogger minSeverity Severity } // Create a new syslog sink. "log/syslog".Writer implements Syslogger. func NewSyslogSink(syslogger Syslogger) *SyslogSink { return &SyslogSink{ s: syslogger, minSeverity: SevDebug, } } func (ss *SyslogSink) SetSeverity(sev Severity) { ss.minSeverity = sev } func (ss *SyslogSink) ReceiveLocally(sev Severity, format string, params ...interface{}) { ss.ReceiveFromChild(sev, format, params...) } func (ss *SyslogSink) ReceiveFromChild(sev Severity, format string, params ...interface{}) { if sev > ss.minSeverity { return } s := fmt.Sprintf(format, params...) switch sev { case SevEmergency: ss.s.Emerg(s) case SevAlert: ss.s.Alert(s) case SevCritical: ss.s.Crit(s) case SevError: ss.s.Err(s) case SevWarn: ss.s.Warning(s) case SevNotice: ss.s.Notice(s) case SevInfo: ss.s.Info(s) default: ss.s.Debug(s) } } xlog-1.0.0/terminal-null.go000066400000000000000000000002141267613016700156010ustar00rootroot00000000000000// +build !darwin,!freebsd,!openbsd,!netbsd,!linux,!windows package xlog import "io" func isTerminal(w io.Writer) bool { return false } xlog-1.0.0/terminal.go000066400000000000000000000004111267613016700146300ustar00rootroot00000000000000// +build darwin freebsd openbsd netbsd linux windows package xlog import "io" import "github.com/mattn/go-isatty" func isTerminal(w io.Writer) bool { wf, ok := w.(interface { Fd() uintptr }) if !ok { return false } return isatty.IsTerminal(wf.Fd()) } xlog-1.0.0/writersink.go000066400000000000000000000030331267613016700152210ustar00rootroot00000000000000package xlog import "os" import "io" import "time" import "fmt" import "github.com/shiena/ansicolor" // Sink which writes each log message on a line to an io.Writer. type WriterSink struct { Systemd bool // Use systemd-format output: "<3>some-log-message" w io.Writer minSeverity Severity isTerminal bool severityString map[Severity]string } func NewWriterSink(w io.Writer) *WriterSink { ws := &WriterSink{ w: w, minSeverity: SevTrace, isTerminal: isTerminal(w), } ws.isTerminal = false if ws.isTerminal { // windows terminal colour compatibility ws.w = ansicolor.NewAnsiColorWriter(ws.w) ws.severityString = ansiSeverityString } else { ws.severityString = severityString } return ws } func (ws *WriterSink) SetSeverity(sev Severity) { ws.minSeverity = sev } func (ws *WriterSink) ReceiveLocally(sev Severity, format string, params ...interface{}) { ws.ReceiveFromChild(sev, format, params...) } func (ws *WriterSink) ReceiveFromChild(sev Severity, format string, params ...interface{}) { if sev > ws.minSeverity { return } msg := ws.prefix(sev) + fmt.Sprintf(format, params...) + "\n" io.WriteString(ws.w, msg) } func (ws *WriterSink) prefix(sev Severity) string { if ws.Systemd { return fmt.Sprintf("<%d>", sev.Syslog()) } return fmt.Sprintf("%s [%s] ", time.Now().Format("20060102150405"), ws.severityString[sev]) } // A sink which writes to stderr. This is added to the root sink by default. var StderrSink *WriterSink func init() { StderrSink = NewWriterSink(os.Stderr) } xlog-1.0.0/xlog.go000066400000000000000000000110271267613016700137730ustar00rootroot00000000000000// Package xlog provides a hierarchical, configurable logging system suitable // for use in libraries. package xlog import "fmt" import "sync" // Site is the interface exposed to the externals of a package, which uses it // to configure the logger. This is the other side of a Logger. type Site interface { // The facility name. Name() string // Sets the severity condition. SetSeverity(severity Severity) // Set the sink which will receive all messages from this logger. SetSink(sink Sink) } var loggersMutex sync.RWMutex var loggers = map[string]*logger{} // Creates a logger which is subordinate to another logger. // // All log messages will be forwarded through the parent logger, meaning that // any filtration or forwarding settings set on the parent logger will // also apply to this one. // // The name of the logger is formed by appending the name given to the name // of the parent logger and ".". If site is nil, behaves like New(). func NewUnder(name string, site Site) (Logger, Site) { if site == nil { return New(name) } sink, ok := site.(Sink) if !ok { panic("site does not implement sink") } l, s := New(site.Name() + "." + name) s.SetSink(sink) return l, s } // Creates a new logger. // // While there are no particular restrictions on facility names, the preferred // convention for the facility name is a dot-separated hierarchy of words // matching [a-zA-Z0-9_-]+. Hyphens are preferred over underscores, and // uppercase should be avoided in most cases. // // The facility name should reflect the package and, if the package's // status as a subpackage is of particular significance or grouping // is desirable, a parent package. // // For example, if you have a package foo which has 10 subpackages which // implement different parts of foo, you might give them facility names like // "foo.alpha", "foo.beta", "foo.gamma", etc. // // Typical usage: // // var log, Log = xlog.New("facility name") // func New(name string) (Logger, Site) { loggersMutex.Lock() defer loggersMutex.Unlock() if _, ok := loggers[name]; ok { panic(fmt.Sprintf("Logger name conflict: logger with name %s already exists", name)) } log := &logger{ parent: rootLogger, maxSeverity: SevTrace, name: name, } loggers[name] = log return Logger{log}, log } // Like New, but the created logger by default doesn't output anything but the // most severe errors. Intended for use by libraries so that consuming code // needs to opt in to log output by that library. func NewQuiet(name string) (Logger, Site) { l, s := New(name) s.SetSeverity(SevCritical) return l, s } type logger struct { maxSeverity Severity name string parent Sink } // Sink is implemented by objects that can receive log messages from loggers // deeper in the hierarchy. type Sink interface { ReceiveLocally(sev Severity, format string, params ...interface{}) ReceiveFromChild(sev Severity, format string, params ...interface{}) } func init() { RootSink.Add(StderrSink) } var rootLogger = &logger{ parent: &RootSink, maxSeverity: SevTrace, } // The root logger. var Root Site = rootLogger // The sink which is used by default by the root logger. var RootSink MultiSink func (l *logger) Name() string { return l.name } func (l *logger) SetSeverity(sev Severity) { l.maxSeverity = sev } func (l *logger) SetSink(sink Sink) { l.parent = sink } func (l *logger) ReceiveLocally(sev Severity, format string, params ...interface{}) { format = l.localPrefix() + format // XXX unsafe format string l.remoteLogf(sev, format, params...) } func (l *logger) remoteLogf(sev Severity, format string, params ...interface{}) { if sev > l.maxSeverity { return } if l.parent != nil { l.parent.ReceiveFromChild(sev, format, params...) } } func (l *logger) ReceiveFromChild(sev Severity, format string, params ...interface{}) { l.remoteLogf(sev, format, params...) } func (l *logger) localPrefix() string { if l.name != "" { return l.name + ": " } return "" } // Calls a function for every Site which has been created. // // Do not attempt to create new loggers from the callback. func VisitSites(siteFunc func(s Site) error) error { loggersMutex.RLock() defer loggersMutex.RUnlock() for _, v := range loggers { err := siteFunc(v) if err != nil { return err } } return nil } // LogClosure can be used to pass a function that returns a string // to a log method call. This is useful if the computation of a log message // is expensive and the message will often be filtered. type LogClosure func() string func (c LogClosure) String() string { return c() }