When you’re writing libraries and applications in Go there is one glaring problem. Logging is all over the place. This is due to there being no standard interface for logging. So, libraries and applications both include logging libraries that are different from each other. This leads to log sprawl.
For example, look in the Kubernetes dependencies and you’ll see references to about 10 different logging libraries. Several do the same thing and they are present just because the libraries use them.
This shouldn’t be the case. Other languages have solved this. Logging should be boring infrastructure. Libraries use an API to log and the implementation that’s used is specified by the application that pulls everything together.
There is a pretty simple way we can do better.
In Go logging there are actually two problems.
First, there are two styles of logging. On one side we have logging levels using numbers. From what I can tell, this has come out Google from their internal handling. Libraries like glog and klog provide this kind of logging.
On the other side we have logging libraries that use names like debug, info, warning, error, and so on to list their levels. This is similar to syslog (a documented standard) but the levels are different. Libraries like logrus fall into this camp.
Sidebar: What About The Standard Library
The Go standard library does have a log package. Isn’t this enough? The simple reason it is not enough is that so many other logging libraries were written to meet a need. If it had been enough we would not have the mess of Go logging we have today.
A Simple Solution
The simple solution is inspired from what PHP did with PSR-3. PHP doesn’t offer a standard logging interface like more modern languages (i.e. Rust). So, the community created an interface that many could implement. Libraries can use the interface and applications choose the logger.
Being that there are two types of Go logging we have two interfaces.
V-Levels With logr
logr is an interface for the v-level style that has come out of Google. There are implementations for a variety of underlying logging libraries.
In libraries (i.e. packages) the interface can be used. Then in the application (i.e. main package) the implementation can be setup. This makes it possible for others to import packages without importing the logging implementation.
Named Levels With log-go
log-go provides a logging API using the common named levels from trace through fatal. It provides a simple default solution using the standard library if nothing is configured but the expectation is that production one will be used. It has reference implementations for logrus, zap, and even a CLI (with color).
The idea is that libraries and packages can use the API while the application (main package) can setup the implementation.
Can we please leave the logging implementations up to the application rather than the packages. Then we can de-clutter the tangled logging mess.