github.com/ucarion/log
provides structured, canonical, context
-based logs in
Golang on top of any existing logging backend. The core idea of canonical
logging is to output fewer, better logs -- say, one per HTTP request served.
With this package, you will add a bit more context to the log in many places:
// Set a field to the current canonical log line -- this does not output anything.
log.Set("user_cache_latency_seconds", 5)
And then at the end of every request, you fire off a single log:
// This will write out all of the fields you've added using Set, along with a message.
log.Log(ctx, "http_request")
You'll find this approach will give you far more useful logs. For instance, you can easily load your logs into an analytics database, and then perform queries to better understand the performance of your application.
To install this package, run:
go get github.com/ucarion/log
First, you need to choose what backend you want to use. See the Backends section in this README for more, but supposing you wanted to use Logrus:
// All you have to do to enable Logrus as your logger is import:
import _ "github.com/ucarion/log/loggers/logrus"
In most of your code, using github.com/ucarion/log
looks like this:
// Prepare a context to keep track of the log-line properties.
ctx := log.NewContext(context.Background())
// Add some properties to the message.
log.Set(ctx, "start_time", time.Now())
log.Set(ctx, "rpc", "ListUsers")
log.Set(ctx, "err", err)
// Fire off a canonical log line.
log.Log("request")
For a more advanced usage, you can also have nested properties by using
WithPrefix
:
ctx1 := log.NewContext(context.Background())
log.Set(ctx1, "root", "level")
ctx2 := log.WithPrefix(ctx1, "nested")
log.Set(ctx2, "foo", "bar")
// Outputs something like, depending your backend:
//
// { "msg": "example", "data": { "root": "level", "nested": { "foo": "bar" }}}}
log.Log("example")
github.com/ucarion/log
is agnostic to what backend you want to use. But for
your convenience, it ships with support for a few popular backends.
To use github.com/ucarion/log
with the standard library log
package, just import:
import _ "github.com/ucarion/log/loggers/log"
See examples/log
for a working example you can play
with. See the GoDocs for details on how you can use other loggers than the
standard stdlib logger.
To use github.com/ucarion/log
with
Logrus, just import:
import _ "github.com/ucarion/log/loggers/logrus"
See examples/logrus
for a working example you can
play with. See the GoDocs for details on how you can use other loggers than the
standard Logrus logger.
To use github.com/ucarion/log
with Uber's
Zap, just import:
import _ "github.com/ucarion/log/loggers/zap"
You'll also need to update the global logger, if you haven't done so already. You can do this by running:
// You could also use NewDevelopment or NewProduction, or a custom Zap logger.
zap.ReplaceGlobals(zap.NewExample())
See examples/zap
for a working example you can play
with. See the GoDocs for details on how you can use other loggers than the
global Zap logger.
To use github.com/ucarion/log
with Segment's
events
, just import:
import _ "github.com/ucarion/log/loggers/events"
See examples/events
for a working example you can
play with. See the GoDocs for details on how you can use other loggers than the
standard events
logger.
Implementing your own custom backend for github.com/ucarion/log
is just a
question of updating log.Logger
, which just requires confirming to an
interface:
var Logger interface {
Log(msg string, fields map[string]interface{})
}
For example, here's some working code that uses fmt.Println
as a logging
backend:
type fmtLogger struct{}
func (l *fmtLogger) Log(msg string, fields map[string]interface{}) {
fmt.Println("my custom logger", msg, fields)
}
func main() {
log.Logger = &fmtLogger{}
// ...
}
See examples/custom
for a working example you can
play with.