87

I have an existing application which does all of its logging against log4j. We use a number of other libraries that either also use log4j, or log against Commons Logging, which ends up using log4j under the covers in our environment. One of our dependencies even logs against slf4j, which also works fine since it eventually delegates to log4j as well.

Now, I'd like to add ehcache to this application for some caching needs. Previous versions of ehcache used commons-logging, which would have worked perfectly in this scenario, but as of version 1.6-beta1 they have removed the dependency on commons-logging and replaced it with java.util.logging instead.

Not really being familiar with the built-in JDK logging available with java.util.logging, is there an easy way to have any log messages sent to JUL logged against log4j, so I can use my existing configuration and set up for any logging coming from ehcache?

Looking at the javadocs for JUL, it looks like I could set up a bunch of environment variables to change which LogManager implementation is used, and perhaps use that to wrap log4j Loggers in the JUL Logger class. Is this the correct approach?

Kind of ironic that a library's use of built-in JDK logging would cause such a headache when (most of) the rest of the world is using 3rd party libraries instead.

Jim Ferrans
  • 30,582
  • 12
  • 56
  • 83
matt b
  • 138,234
  • 66
  • 282
  • 345

7 Answers7

38

One approach I have used successfully is to use slf4j as my primary logging API. I then have slf4j bind to log4j. 3rd party dependencies using other frameworks (like JUL) can be bridged to slf4j.

overthink
  • 23,985
  • 4
  • 69
  • 69
  • 2
    Good link, but I think you meant #jul-to-slf4j – araqnid May 15 '09 at 17:49
  • This sounds like a good approach, except I can't seem to get it to work :( – matt b May 15 '09 at 18:27
  • 2
    Also, I can't believe that a library as popular as ehcache would make a switch to something like java.util.logging - seems very boneheaded – matt b May 15 '09 at 19:34
  • Yeah, it's incredibly frustrating to have to fight with this stuff all time time (well, each time you start some new project, it seems). I'm not sure of ehcache's motivation for the switch. The main benefit I can see of JUL is that it's not another dependency... even if it does suck :) – overthink May 15 '09 at 21:36
  • 1
    @matt b, JUL is present in the Java runtime always so it requires the least external dependencies. It is, however, in my eyes a true example of code written by people not experienced with the usages of that code. The configuration system is rather inconvenient. – Thorbjørn Ravn Andersen Jun 20 '10 at 08:17
  • 1
    The problem you have is that if you bridge SLF4J to JUL, the logging performance is appalling. Specifically each log line you create results in an exception thrown to determine which logger context to use. That creates a lot of overhead and slows down processes – Egwor Dec 07 '13 at 21:39
19

We use SLF4J on our current project and it's worked very well for us. SLF4J is written by Ceki Gülcü, the creator of Log4J, and he's done a really great job. In our code we use the SLF4J logging APIs directly, and we configure SLF4J so that calls from the Jakarta Commons Logging (JCL), java.util.logging (JUL), and Log4J APIs are all bridged to the SLF4J APIs. We need to do that because like you we use third party (open source) libraries that have chosen different logging APIs.

On the bottom of SLF4J, you configure it to use a particular logger implementation. It comes with an internal, or "simple" logger, and you can override this with Log4J, JUL, or Logback. Configuration is all done simply by dropping in different jar files in your classpath.

Originally, we used the Logback implementation, also written by Ceki Gülcü. This is very powerful. However, we then decided to deploy our application to the Glassfish Java EE application server, whose log viewer expects JUL-formatted messages. So today I switched from Logback to JUL, and in just a few minutes I replaced two Logback jars with an SLF4J jar that connects it to the JUL implementation.

So like @overthink, I would heartily recommend using SLF4J in your setup.

Jim Ferrans
  • 30,582
  • 12
  • 56
  • 83
  • 8
    How many times does Ceki need to reinvent a logging framework/fascade ? – mP. Apr 03 '10 at 09:19
  • @mP: Logging may not be glamorous, but it's a crucial need for large-scale commercial-grade software. And SLF4J solves the problem of integrating code that uses disparate logging frameworks (made more urgent by Sun electing to develop java.utils.logging instead of adopting Log4J). – Jim Ferrans Jun 20 '10 at 05:42
  • 3
    @mP, slf4j was necessary because the bad job Sun did with JUL. Logback is a fork of log4j, not a new project. – Thorbjørn Ravn Andersen Jun 20 '10 at 08:19
  • 3
    I found logback to be necessary, if for nothing else, it's not Apache, and it's actually documented. – Spencer Kormos Oct 17 '11 at 17:34
16

There is a simpler alternative than SLF4J to bridge JUL with log4j, see http://people.apache.org/~psmith/logging.apache.org/sandbox/jul-log4j-bridge/examples.html

You just have to put the jul-log4j-bridge on the classpath and add a system property:

-Djava.util.logging.manager=org.apache.logging.julbridge.JULBridgeLogManager

jul-log4j-bridge is not in Maven Central and can be fetched from this repository:

<repository>
  <id>psmith</id>
  <url>http://people.apache.org/~psmith/logging.apache.org/repo</url>
  <releases>
    <enabled>false</enabled>
  </releases>
</repository>

and then used with:

<dependency>
  <groupId>org.apache.logging</groupId>
  <artifactId>apache-jul-log4j-bridge</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <scope>test</scope>
  <exclusions>
    <exclusion>
      <groupId>log4j</groupId>
      <artifactId>apache-log4j-component</artifactId>
    </exclusion>
  </exclusions>
</dependency>

It's also possible to rebuild it from sources with the following steps:

  1. svn co http://svn.apache.org/repos/asf/logging/sandbox/jul-to-log4j-bridge/
  2. edit pom.xml, replace the dependency on log4j:log4j:1.2.15 with log4j:apache-log4j-extras:1.2.17 and remove the dependency on apache-log4j-component
  3. mvn package
Emmanuel Bourg
  • 9,601
  • 3
  • 48
  • 76
  • 4
    I think it's simpler because it can be done without changing your code, you just have to add a system property. SLF4J doesn't propose a similar mechanism yet, you either change the code or the `logging.properties` file. – Emmanuel Bourg Apr 25 '13 at 23:30
  • 1
    This doesn't exist in log4j2, unfortunately :( – BeepDog Sep 30 '13 at 15:23
  • `JulLog4jBridge.assimilate();` o_0 – Bastian Voigt Jan 23 '14 at 16:03
  • 2
    WARNING! `jul-log4j-bridge` uses the never-released `apache-log4j-companions` bundle (a backport from the abandoned `log4j 1.3`). You'll have a hard time building it. Naturally, the bridge itself is abandoned pre-release, too. – ivan_pozdeev Jul 29 '15 at 05:27
  • @ivan_pozdeev Good point, thank you. I've added instructions to build it. – Emmanuel Bourg Jul 30 '15 at 08:28
15

OCTOBER 2014

Since version 2.1 of log4j exists the component log4j-jul, which allows exactly this. Still, in case you are using log4j 1, it has to be possible to upgrade to log4j2 in order to use this approach.

JDK Logging Adapter

Class LogManager

Migrate from log4j 1.x to log4j 2

Marcono1234
  • 5,856
  • 1
  • 25
  • 43
AdrianRM
  • 2,622
  • 2
  • 25
  • 42
  • 2
    As of now (mid 2018) this should be the accepted answer – rmuller Aug 17 '18 at 06:16
  • 1
    For future readers: I confirm this is working. So, basically (1) add this to your pom https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-jul and (2) add the system property in the first link (e.g., in JVM parameters add -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager ) – Hossam El-Deen Apr 15 '20 at 13:19
  • I've noticed having it on the classpath isn't *just* working in a manually configured spring with an embedded tomcat 9.0. Can you provide steps/code? both loggers are working, but tomcat is obviously not using the log4j default console appender. – xenoterracide Jan 21 '21 at 20:15
  • 1
    The biggest disadvantage is that you have to set up the System property "before any calls are made to LogManager or Logger" (might be the reason why it is not working for @xenoterracide). Especially when your project is a dependency of other projects, that is not easily doable in a sane way. An alternative would be to go java.util.logging → SLF4J → Log4j 2. Probably not very performant but at least works (with some limitations from the SLF4J bridge since it only implements a java.util.logging Handler). – Marcono1234 Feb 24 '21 at 18:04
  • Log4j 2 actually has a `Log4jBridgeHandler` class similar to SLF4J's one, but it has not been backported to 2.x yet, see [backport pull request](https://github.com/apache/logging-log4j2/pull/437). – Marcono1234 Feb 27 '21 at 01:02
3

The slf4j site I believe has a bridge for passing java.util.logging events via slf4j (and hence to log4j).

Yes, the SLF4J download contains jul-to-slf4j which I believe does just that. It contains a JUL handler to pass records to SLF4J.

araqnid
  • 127,052
  • 24
  • 157
  • 134
2

@Yishai - Thanks for posting the link to my wiki. The example there redirects JUL to Log4J and I've had it running in a production system for a few years. JBoss 5.x already redirects JUL to Log4J, so I took it out when we upgraded. I have a newer one that redirects to SLF4J, which I use on a few things now. I'll post that when I get a chance.

However, SLF4J already has it:

http://mvnrepository.com/artifact/org.slf4j/jul-to-slf4j

Joshua Davis
  • 3,499
  • 1
  • 26
  • 29
0

you should manually add blew at startup

SLF4JBridgeHandler.removeHandlersForRootLogger()
SLF4JBridgeHandler.install()

demo -> https://gist.github.com/jiahut/654ecc75a13b0a1d8f3b4d5d2d69dc6d

jiahut
  • 1,451
  • 15
  • 14