Do you find java.util.logging sufficient?

Viewed 11109

Per the title, do you find the default Java logging framework sufficient for your needs?

Do you use alternative logging services such as log4j or others? If so, why? I'd like to hear any advice you have regarding logging requirements in different types of projects, and when integrating frameworks is actually necessary and/or useful.

17 Answers

java.util.logging (jul) was unnecessary from the beginning. Just ignore it.

jul in itself has the following downsides:

  • At the time that jul was introduced in Java 1.4 there was already a well established logging framework in wide use: LOG4J
  • the predefined log levels are: SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST. I won't tell you what I personally think about those predefined levels to keep this answer semi-objective.
  • Additional levels can be defined. jul supports up to 4G different log levels which is slightly overkill, IMHO. Less is sometimes more.
  • The most important point: if you dare to define your own log level you are likely to run into a memory leak issue!
    Feel free to read about this effect here:

    It's a pretty interesting read even if you are not planning to use custom levels, btw, since the problem is a wide-spread one that doesn't just apply to jul at all.

  • it resides in the java.* namespace so the implementation can't be exchanged at runtime. This effectively prevents bridging it to SLF4J the same way its possible in case of commons.logging and LOG4J. The way bridging is done for jul has a performance impact. This makes jul the most inflexible logging framework out there.
  • By introducing jul, Sun implicitly defined it to be the "standard java logging framework". This led to the common misconception that a "good Java citizen" should use jul in their libraries or applications.
    The opposite is the case.
    If you use either commons.logging or LOG4j you'll be able to exchange the actually used logging framework, if you ever need to, by bridging to SLF4J. This means that libraries using either commons.logging, LOG4J or SLF4J can all log to the same logging target, e.g. file.

I'd personally suggest to use the SLF4J+Logback combo for all logging purposes. Both projects are coordinated by Ceki Gülcü, the guy behind LOG4J.
SLF4J is a worthy (but unofficial since it's not from the same group) successor of commons.logging. It's less problematic than CL because it statically resolves the actually used logging backend. Additionally, it has a richer API than CL.
Logback, on the other hand, is the (un)official successor of LOG4J. It implements SLF4J natively so there's no overhead caused by any wrapper.

Now you may downvote me if you still think I deserve it. ;)

Logging Dependencies with Third Party Libraries

Java JDK logging in most cases is not insufficient by itself. However, if you have a large project that uses multiple open-source third party libraries, you will quickly discover that many of them have disparate logging dependencies.

It is in these cases where the need to abstract your logging API from your logging implementation become important. I recommend using slf4j or logback (uses the slf4j API) as your API and if you want to stick with Java JDK logging, you still can! Slf4j can output to many different logger implementations with no problems.

A concrete example of its usefulness happened during a recent project: we needed to use third-party libs that needed log4j, but we did not want to run two logging frameworks side by side, so we used the slf4j log4j api wrapper libs and the problem was solved.

In summary, Java JDK logging is fine, but a standardized API that is used in my third party libraries will save you time in the long run. Just try to imagine refactoring every logging statement!

SLF4J is the new kid. I've done a little work with it and it's pretty nice. It's main advantage is parametrized logging, which means you do this:

logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);

Rather than this:

logger.debug("The new entry is " + entry + ". It replaces " + oldEntry + ".");

And all that string manipulation is done only if the statement is actually logged. Looks cleaner too.

It should be noted that SLF4J is a wrapper like commons-logging, though it claims to be less prone to commons-logging's classloader problems.

We use java.util.logging throughout. Also for large projects. There is a few things you should tweak (e.g. the default formatting) but that's off the real point. I find the number of logging frameworks in Java and the feature creep they implemented rather annoying and somewhat embarassing for the Java community. The level of religuous debate about logging is a sure sign that something went seriously wrong.

What JUL gives you is a simple but sufficient API and a single place to configure what log output you want to see (logging.properties or JMX...). And its always there and stable.

All code that wants to log should stick to the standard conventions (default level is INFO) and otherwise do no more but use loggers of a meaningful name (e.g. package or class name) and you will be fine.

Unless there is a compelling reason to use something outside of the JDK I prefer to use what is provided by Sun.

Many of the projects that use the Log4J logging were using it before the "standard" logging API existed.

I was unable to figure out how to control the logging level of individual classes in the java.util.logging framework, something that is possible in log4j. If I'm having trouble diagnosing a bug or there is a high-traffic class that logs important information, I can change the level for a single class to log more and leave the rest of my classes relatively quiet.

N.B. It could be that I couldn't figure out how to do it, or java.util.logging could have changed since I tried.

java.util.logging is nice but does not have a configuration which is picked up by default from the classpath. That is rather a pain point for us as we have many deployments which does not share logging configurations and it is rather messy to do this in j.u.l.

Log4j is currently not being developed much so if there is a need for development on the backend part logback is at the moment the most dynamic option in my opinion.

(caveat: involved in some obscure development of slf4j and logback but that is due to and not causing the statements I make above :) )

I thought I'd use log4j -- as mentioned by @ScArcher2, just because everyone does. But after dealing with both options, I found out java.util.logging is far enough sufficient for most of my needs -- and I am talking about a huge system with many spread components working together.

So, in my opinion, there is no need to use alternative services. Java.util.logging is powerful enough for most cases.

It's pretty easy to write a j.u.l LogManager class which will defer all logging to a bespoke implementation which uses Log4J. This means that you can use log4j but still have the nice feature that libraries which log using j.u.l can be controlled as-if they had used Log4J.

Having used both (and commons-logging), I have to say that the thing which really, really, really annoys me is this:

log4j.error("An Exception", e);

jul.severe("An Exception", e); // GRRR! no such method

jul.log(Level.SEVERE, "An Exception", e); //Must use this method

Why did they make this design choice? Why? The other thing is that there's no PatternFormatter which ships with j.u.l - you have to roll your own.

That said, I'm erring to use j.u.l from now on as it cuts down on external dependencies and isn't any more complicated to use.

In the projects I work on, we tend to use commons-logging from Jakarta. That is not a logging system itself, instead it is able to wrap some of the most common loggers - log4j, java.util.logging or others.

With that, it is relatively easily possible to switch the logging based on environment the application is deployed to (a developer may want to use simplelog or java.util.logging on his machine because of ease of maintenance, while on a SIT system, log4j with a common configuration for all apps may be deployed, etc.)

One of the problems I have with ALL logging frameworks is that unless everyone on your team spends the time to become proficient at exactly how to set it up and control it, you never know if a given debug statement will print out or not.

You may have a level (debug) turned off, or you may have one package turned off.

I've wasted too much time assuming that a debug statement would print and it doesn't. Now I mostly rely on System.out.println() and just go through and delete or convert them when I'm done debugging.

I know this doesn't answer your question--I'm just saying that you may want to consider how much justification you have before adding complexity.

Logging isn't that complicated and is certainly justified on most larger projects.

Personally I use Simple Logger, but at work I use our corporate wrapper to the JDK logger. I use Simple Logger, due to the ease of getting it set up and the fact that it supports logging of 7 levels between Fatal and Ludicrous.

If you need logging in your app then youve probably done smething really wrong. I would argue that reporting the occasional problem is ok, but having debug, info etc statements in lots of classes with logic is plain wrong. Any large application with logging statements in most of its logic filled classes is going to amount to information overload even if one picks just the right loggers on. Most of the time the information will be incomplete, noisy or the actual information you need is plain missing.

Im basically saying that you should only need to write debug statements to inform the user about program reactions to external factors

  • formating problem in a text based config file.
  • Problems with opening or locating a required file.
Related