Logrus; a structured logger for Go

Nov 25, 2019 | Golang

Logrus is a structured logger for Golang, which offers modularity, flexibility, and compatibility (github). Most projects can switch over to using logrus with a single Linux command. With an incredibly small learning curve and a plethora of extensions, logrus could be the right choice for your project.

Hello World

Logrus is one of the easiest hello world’s you can find, here it is, in a basically a single line of code.

package main

import(
	"github.com/sirupsen/logrus"
)

func main(){
	logrus.WithFields(logrus.Fields{
        	"foo":"bar"}).Info("hello world")
}

Injection

One of the places where logrus shines the brightest is its ability to be swapped into a codebase. You can easily change the global logger, which can be optimal for older, large codebases, since injecting a logger would not be reasonable.
package main

import (
	log "github.com/sirupsen/logrus"
)

type msFormater struct{}

func (mf msFormater) Format(entry *log.Entry) ([]byte, error) {
	entry.Data["module"] = "safari"

	formatter := log.TextFormatter{}
	return formatter.Format(entry)
}

func main() {
	log.SetFormatter(msFormater{})
	log.SetLevel(log.DebugLevel)
	log.Info("hello")
}

Benchmark

While Logrus offers significantly more features than the built-in log package, it is also important to take performance into account. For this benchmark, I will be testing 4 logging cases: large string, map, map with small members, and large string with caller reporting. The code used for this benchmark can be found here.

BenchmarkLogrus-16                   	  358696      3222 ns/op
BenchmarkLog-16                      	 4048160       330 ns/op
BenchmarkLogrusMap-16                	  331330      3523 ns/op
BenchmarkLogMap-16                   	  638674      2005 ns/op
BenchmarkLogrusMapSmallMembers-16    	  326095      3625 ns/op
BenchmarkLogMapSmallMembers-16       	  624159      1935 ns/op
BenchmarkLogrusCallerReport-16       	  181448      6657 ns/op
BenchmarkLogCallerReport-16          	 1246078      1024 ns/op

The built-in log parser was able to beat out logrus by a factor of 10:1 when it comes to logging pure text via the Print function call. As the complexity increases, Logrus gains traction against the build-in package. When logging a map, Logrus managed to get all the way down to a 1.75:1 ratio. Now, I wonder if Logrus would be able to beat out the default logger if we leverage this to its advantage. So, I put it in the most minimal mode I could find, and then ran it on a map with 1000 members. 

BenchmarkLogrusBestCase-16           	    1518    759788 ns/op
BenchmarkLogBestCase-16              	    1750    683142 ns/op

Sadly, it seems like the default logger will always have a slight performance advantage over Logrus. The best result I was able to produce was a 1.1:1.0 ratio, which isn’t bad. However, this was done under very artificial conditions, having all of the features disabled. From the results, it is fairly safe to say that the difference in performance mainly results from the extra bells and whistles provided by the library.

Personally, despite the extra overhead, I have found the additional features to be incredibly useful. Pluggable formatting makes it extremely easy to be compliant with any log analysis platform. Additionally, the ability to have different verbosity levels is incredibly helpful for reducing the cost of your log ingestion pipeline.

logrus

Logrus; a structured logger for Go

Logrus is a structured logger for Golang, which offers modularity, flexibility, and compatibility (github). Most projects can switch over to using logrus with a single Linux command. With an incredibly small learning curve and a plethora of extensions, logrus could be...
c++

How to install the Boost C++ libraries

The Boost C++ libraries are a set of free peer-reviewed C++ libraries. They are intended to be useful for a wide variety of applications and portable. Boost just makes life easier, here is how to install it on Linux. Installing Boost using a package manager The...