Logging in Golang

Native Go Logging

Go offers native logging library:

Logging to Stdout/Stderr

$ mkdir logging-frameworks && cd logging-frameworks
$ cat > native.go <<EOF
package main

import "log"

func main() {
	log.Println("Hello world!")
	log.Debug("Debugging is fun")
	log.Info("Something is interesting!")
	log.Warn("Something bad may come!")
	log.Error("Something must be wrong!")
	log.Fatal("OMG!")
}
EOF

$ go run native.go
INFO[0000] Hello world!
INFO[0000] Something is interesting!
WARN[0000] Something bad may come!
ERRO[0000] Something must be wrong!
FATA[0000] OMG!
exit status 1

The code above prints the text "Hello world!" to the standard error, but it also includes the date and time, which is handy for filtering log messages by date.

Logging to a File

A file named logs.txt will be created with content:

You can basically output your logs to any destination that implements the io.Writer interface, so you have a lot of flexibility when deciding where to log messages in your application.

Creating custom loggers

Output in logs.txt:

Log flags

There are log flags we can use to enhance the logs:

So:

Community Logging Frameworks

Surprisingly, there is a long list of community logging frameworks, with different design philosophies. Let's name some of the popular ones

  • glog - Leveled execution logs for Go.

  • logrus - Structured logger for Go.

  • zap - Fast, structured, leveled logging in Go.

Let's try out logrus.

logrus

Get Started

As logrus is fully compliant to Golang's standard logging APIs, it can be very easy to get started:

Logging in JSON

Log levels

Unlike the standard log package, logrus supports log levels.

We will get:

Notice that the Debug level message was not printed. To include it in the logs, set log level to equal log.DebugLevel:

Logging Method Name

Using Fields

Default Fields

Often it's helpful to have fields always attached to log statements in an application or parts of one. For example, you may want to always log the request_id and user_ip in the context of a request. Instead of writing log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip}) on every line, you can create a logrus.Entry to pass around instead:

We got this -- note that only user activity logs logged with extra fields:

Hooks

There are many hooks, besides the built-in ones: https://github.com/sirupsen/logrus/wiki/Hooks

A simple writer-based hook mechanism can be implemented like:

Now:

Formatters

The built-in logging formatters are logrus.TextFormatter, logrus.JSONFormatter.

There is a series of 3rd party fomatters too:

References

Last updated

Was this helpful?