log
Log is a simple, highly configurable, Structured Logging library
Why another logging library?
There's allot of great stuff out there, but also thought a log library could be made more configurable using per handler log levels.
Features
- Logger is simple, only logic to create the log entry and send it off to the handlers and they take it from there.
- Ability to specify which log levels get sent to each handler
- Built-in console, syslog, http, HipChat, json and email handlers
- Handlers are simple to write + easy to register + easy to remove
- Default logger for quick prototyping and cli applications. It is automatically removed when you register one of your own.
- Logger is a singleton ( one of the few instances a singleton is desired ) so the root package registers which handlers are used and any libraries just follow suit.
- Convenient context helpers
GetContext
&SetContext
- Works with go-playground/errors extracting types and tags when used with
WithError
, is the default - Works with pkg/errors when used with
WithError
, must set usingSetWithErrFn
- Works with segmentio/errors-go extracting types and tags when used with
WithError
, must set usingSetWithErrFn
Installation
Use go get
go get -u github.com/go-playground/log/v7
Usage
import the log package, it is recommended to set up at least one handler, but there is a default console logger.
package main
import (
"errors"
"github.com/go-playground/log/v7"
"github.com/go-playground/log/v7/handlers/console"
)
func main() {
// There is a default logger with the same settings
// once any other logger is registered the default logger is removed.
cLog := console.New(true)
log.AddHandler(cLog, log.AllLevels...)
// Trace
defer log.WithTrace().Info("time to run")
log.Debug("debug")
log.Info("info")
log.Notice("notice")
log.Warn("warn")
log.Error("error")
// log.Panic("panic") // this will panic
log.Alert("alert")
// log.Fatal("fatal") // this will call os.Exit(1)
err := errors.New("the is an error")
// logging with fields can be used with any of the above
log.WithError(err).WithFields(log.F("key", "value")).Info("test info")
// predefined global fields
log.WithDefaultFields(log.Fields{
{"program", "test"},
{"version", "0.1.3"},
}...)
log.WithField("key", "value").Info("testing default fields")
// or request scoped default fields
logger := log.WithFields(
log.F("request", "req"),
log.F("scoped", "sco"),
)
logger.WithField("key", "value").Info("test")
}
Adding your own Handler
package main
import (
"bytes"
"fmt"
"github.com/go-playground/log/v7"
)
// CustomHandler is your custom handler
type CustomHandler struct {
// whatever properties you need
}
// Log accepts log entries to be processed
func (c *CustomHandler) Log(e log.Entry) {
// below prints to os.Stderr but could marshal to JSON
// and send to central logging server
// ---------
// |----------> | console |
// | ---------
// i.e. ----------------- ----------------- Unmarshal ------------- --------
// | app log handler | -- json --> | central log app | -- to -> | log handler | --> | syslog |
// ----------------- ----------------- Entry ------------- --------
// | ---------
// |----------> | DataDog |
// ---------
b := new(bytes.Buffer)
b.Reset()
b.WriteString(e.Message)
for _, f := range e.Fields {
fmt.Fprintf(b, " %s=%v", f.Key, f.Value)
}
fmt.Println(b.String())
}
func main() {
cLog := new(CustomHandler)
log.AddHandler(cLog, log.AllLevels...)
// Trace
defer log.WithTrace().Info("took this long")
log.Debug("debug")
log.Info("info")
log.Notice("notice")
log.Warn("warn")
log.Error("error")
// log.Panic("panic") // this will panic
log.Alert("alert")
// log.Fatal("fatal") // this will call os.Exit(1)
// logging with fields can be used with any of the above
log.WithField("key", "value").Info("test info")
}
Log Level Definitions
DebugLevel - Info useful to developers for debugging the application, not useful during operations.
InfoLevel - Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required.
NoticeLevel - Normal but significant condition. Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required.
WarnLevel - Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time.
ErrorLevel - Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time.
PanicLevel - A "panic" condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call.
AlertLevel - Action must be taken immediately. Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection.
FatalLevel - Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection. ( same as SYSLOG CRITICAL )
Handlers
Pull requests for new handlers are welcome, please provide test coverage is all I ask.
Package Versioning
I'm jumping on the vendoring bandwagon, you should vendor this package as I will not be creating different version with gopkg.in like allot of my other libraries.
Why? because my time is spread pretty thin maintaining all of the libraries I have + LIFE, it is so freeing not to worry about it and will help me keep pouring out bigger and better things for you the community.
Benchmarks
Run on Macbook Pro 15-inch 2017 using go version go1.9.4 darwin/amd64
NOTE: only putting benchmarks at others request, by no means does the number of allocations make one log library better than another!
go test --bench=. -benchmem=true
goos: darwin
goarch: amd64
pkg: github.com/go-playground/log/benchmarks
BenchmarkLogConsoleTenFieldsParallel-8 2000000 946 ns/op 1376 B/op 16 allocs/op
BenchmarkLogConsoleSimpleParallel-8 5000000 296 ns/op 200 B/op 4 allocs/op
Special Thanks
Special thanks to the following libraries that inspired