Skip to main content

Simplifying logging with Maven and SLF4J

UPDATE:Ceki commented below which prompted me to rewrite the third paragraph.

UPDATE 2:I have a better way of configuring Maven and SLF4J now.

The mismatch between logging frameworks always seems to come up in projects I've developed over the years. Little-by-little I've learned and relearned how to navigate the nest of runtime logging that occurs in non-trivial applications. With my latest project I think I finally converged on a solution that I'll carry forward to future projects.

So what am I really talking about? Have you ever been stumped, even for a short time, about where a certain log message is going and why it might not appear in your log? Often this happens when you are trying to debug an issue with a third-party library that's using a different logging implementation them your application. If you are nodding from familiarity, skip the next paragraph.

Let's start from the beginning. There are several logging implementations available for Java, the best known being Log4J and the java.util.logging (JUL) API that was added in JDK 1.4. You may also encounter Apache commons-logging which is a logging facade for library developers to abstract their logging so library users are free to choose their own implementation such as Log4J. But commons-logging has well-documented issues so that's where slf4j comes in as my logging facade of choice. I actually code all my new applications to use the slf4j API directly because it adds functionality over the logging implementations like parameterized log messages that are only evaluated if the associated logging level is enabled. But that's tangent to this post.

So how have you solved the usage of multiple logging implementations? In the past I've tried different techniques:

  1. Configure each framework separately and have them write to their own log files.
    • Pro: Is there one?
    • Con: You need to monitor multiple files
    • Con: You need to understand the usage and configuration of each framework.
    • Con: If you are in a J2EE container you lose the log adminstration it provides.
  2. Redirect everyone to standard out and redirect standard out to a file.
    • Pro: Its all going one place.
    • Con: Its all in standard out, even errors which can make adminstration tools fail to filter messages properly.
    • Con: You still need to configure each secondary framework including message formatting so all log lines follow the same pattern.
  3. Write and connect bridges for each secondary framework so that they will log to one framework that is responsible for writing to the file, which I'll call the primary framework.
    • Pro: Its all going one place and category names, and levels are preserved through to the primary framework.
    • Pro: If the primary framework supports programmatic changes to log levels, it works for all frameworks.
    • Pro: If you are in a J2EE container that support live updating of log levels, it works for everything.
    • Con: You need to know what you are doing to develop the bridges, configure the bridge in each secondary framework and connect it all together properly.

So what's the magic solution I found? Well its a variation of #3 but it doesn't require any coding or any real knowledge of how to configure secondary frameworks. And I'll show you how to accomplish it using Maven and a logging facade API called SLF4J.

Here is the overview of the steps:
  1. Decide what the primary framework will be.
  2. Ban all secondary logging framework in your projects.
  3. Update your dependencies to exclude the banned dependencies.
  4. Configure your project to depend on drop-in replacements of each secondary logging framework from SLF4J and to use SLF4J to send everything to your primary framework.

Decide what the primary framework will be.

For my latest project, I'll be deploying to Glassfish which use JUL internally and has support in its admin console for live updating log levels without restarting the server, so it was easy to pick JUL as my primary framework.

Ban all secondary logging frameworks



Add the following plugin to your pom.xml


Add exclusions

This is where mvn dependency:tree -Dincludes=log4j:log4j is really helpful. If you try to build now, your build fail on the enforcer rule. Run this command to find which dependency is including log4j and add the necessary <exclusion>. Repeat until you find no more dependencies on log4j. Repeat for each of the banned dependencies.

Add dependency on SLF4J

Add the following to your pom.xml


Conclusion


So in 4 steps you can redirect all your logging to your primary logging framework without changing a line of code!

Comments

Ceki said…
Hi Brian,

Thank you for this article. I'd like to observe that apache commons-logging is not a logging implementation but a logging facade and only a logging facade.

Cheers,
Thanks Ceki, I updated the post to clarify that.
Javin Paul said…
Excellent article , you have indeed covered topic in details with code examples and explanation. I have also blogged some of my experience as 10 tips on logging in Java

Thanks
Javin
Yegor said…
Brian, you can also use http://www.jcabi.com/jcabi-maven-slf4j/, which does the same job, but without any coding. Just add a dependency to the project and use SLF4J as usual. I'm a developer of that binding.
Daniel said…
The SLF4J FAQ mentions three options for excluding other frameworks in Maven: SLF4J FAQ.

Interestingly IDEs, under default configuration, can add other logging framework jars onto the classpath; obscuring SLF4J.

Popular posts from this blog

TeamCity build triggering by GitHub

So I started using GitHub for a side project and discovered their very cool feature of service hooks. A service hook allows a repository administrator to setup a callback to another service when a commit is made to the repository. For example it can send an email, or chat a message via Jabber.

Now continuous integration servers, like TeamCity, can poll source control systems every few minutes to see if any changes have been committed. But wouldn't it be more efficient to use a service hook to trigger a build?
Looking at GitHub's service hooks, there wasn't one already available to callback a TeamCity server, but right on that same page was a link to the open source repository for GitHub Service Hooks. They "eat their own dogfood" so to speak and make it very easy to contribute new service hooks back to them. So I took an evening, did my first Ruby coding in a while which included more time getting Ruby setup and working on my Macbook than actually coding. In a …

Paperless

I've been slowly going paperless over the past decade. The first step on my journey started in 2000 when I signed up to use a payment service, PayTrust, to receive my incoming bills, scan them, and put them online for me to pay. The next major step was probably when I got a digital camera to replace my traditional film cameras. It might not be considered a "paperless" use case, but it has lead to very little hardcopies over the years as monitors and HDTV with screensavers and AppleTVs have become so beautiful.  Back to the paperless office, my next big step was eFileing my taxes but that didn't come until about 5 years later. Then suddenly about two years ago, I hit a real shift in my desire to go completely paperless when I got my iPad and installed Evernote.

digital notes...
If you aren't familiar with Evernote its an excellent app, available on all the major desktop and mobile OSes, that makes note-taking and organizing really simple. The killer feature is …

Simplifying logging with Maven and SLF4J (Part 2)

So in my previous post I explained how to simplify your logging with Maven and SLF4J. If you haven't read it yet, please do before reading more.  Since then I've discovered an easier and cleaner way to remove the secondary frameworks from your Maven dependency tree.

Here's a revised overview of the steps:

Decided which logging framework will be your primary, aka who will actually write to your log file.Define the dependency scope of all the secondary frameworks to be 'provided'.Configure your project to depend on drop-in replacements of each secondary framework from SLF4J.
Define secondary frameworks as provided
Use the dependencyManagement section for this. Its used when you might have a dependency transitively.
Add dependency on SLF4J Add the following to your pom.xml
Conclusion
So now in only 3 steps you can redirect all your logging to your primary logging framework without changing a line of code!