Java Logging Quickstart

On a typical application’s dependency graph we could find as many as 4 libraries relating to logging. Why do we need so many? What do each of the libraries actually do? slf4j? logback? core/classic? log4j2? This article attempts to answer some of these questions.

Lets start with a real example POM from an application I own:

<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-api</artifactId>
	<version>${slf4j.version}</version>
</dependency>
<dependency>
	<groupId>ch.qos.logback</groupId>
	<artifactId>logback-classic</artifactId>
	<version>${logback.version}</version>
</dependency>
<dependency>
	<groupId>ch.qos.logback</groupId>
	<artifactId>logback-core</artifactId>
	<version>${logback.version}</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.7.7</version>
</dependency>

We can categorise each of these logging dependencies into 3 types:

  • Facades
  • Implementations
  • Adapters

The nature of your project (Application or Library) and how poorly libraries outside your control have been written will largely govern which of the above categories you’ll need to include in your dependency chain. As a rule:

  • If you’re writing a library that has no dependencies, you will only ever need to include Facades.
  • If you’re writing an application, you will need to include both Implementations and Facades.
  • If you’re writing an application that depends on libraries where the authors have failed to give proper thought to their logging strategy, you will most likely need to include adapters to deal with the fallout arising from this.

For the purposes of this article, an application is a stand-alone block of code that either has or uses a main method, and a library is just a bunch of classes that provide some functionality in the context of an application.

Lets talk about each of the dependencies from the POM in turn.

slf4j-api

SLF4J-API (Simple Logging Facade For Java) is as the name suggests a logging facade - i.e. a layer of abstraction, which allows us to define the concept of “logging” without deciding if we’re logging to disk or STDOUT, or which classes we want to filter, or what level we want to debug at. You can think of this library as being similar to an abstract class that somebody else later tunes to their needs. By including this library on the classpath, we can allow our libraries and applications to perform logging at the ‘conceptual’ level. Note that this is just a facade and that without an implementation backing it, nothing will happen, no messages will be logged. However, a facade does at least allow us to start writing code, so here’s what a typical usage pattern looks like:

package uk.co.solong.example.logging;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Example {

    private static final Logger logger = LoggerFactory.getLogger(Example.class);

    public void doNothing() {
        logger.info("Doing nothing");
    }

}

Note the two classes imported Logger, LoggerFactory, we used these to create a logger (passing in the name of the class), and said that a message “Doing nothing” should be logged at the info level. But we never said if this should be written to disk; this is for the implementation to deal with, indeed there are many implementations to chose from, their performance characteristics are different and so by binding our library to a facade rather than an implementation we allow ourselves the freedom to not only chose a different implementation, but to not have to recompile our code when we chose to switch.

logback-classic and logback-core

Logback classic and Logback core are 2 artifacts belonging to the logging *implementation known as logback, this means that these libraries are responsible for actually writing stuff to disk, and facilitate the configuration of logging from a threading perspective, provide filtering and other “concrete implementation” related stuff. If logging performance is of concern to you, then your implementation of choice is one that you’ll want to think carefully about. log4j and log4j 2, are two alternaties to the logback implementations and you can pretty much swap them out on a 1:1 basis (because we were smart enough to use a facade). If you were writing an application, you would want to pick one, however, if you are writing a library

jcl-over-slf4j

JCL over slf4j is an adapter which is designed to send calls made to the Jakarta Commons Logging through the slf4j api. Why would you need to include this? Some libraries that you have might be really old, or the developers might not be thinking about logging properly and just slap any old logging jar on. If you don’t include this, and there are calls to jcl that go unrouted, you can often see symptoms such as log entries appearing in STDOUT, or log entries ignoring your log-level suppression rules.