Question

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.

Was it helpful?

Solution

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!

OTHER TIPS

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. ;)

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.

The JDK logging facilities have always done what I need them to do - never had a problem with it.

To me, third party logging tools are neither necessary nor desirable.

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.

We use log4j with commons logging. I think we just use them because everyone else does. That and we were using log4j before the jdk supported logging.

Edit: The just because everyone else does was a joke, but probably why I started out with log4j and commons logging.

Here are some reasons to use commons logging.

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.)

It all really depends on what your logging requirements are. It is not just the API that the application developers use that you look at, and frankly that's the least of the issue as logging APIs for the most part are easy to adapt no matter which choice you make.

The important part is what kind of logging configuration you require for operations and they should tell you what they require.

  1. It can be as simple as text files that roll over.
  2. It can be more complicated like logging to a JMS or database.
  3. It may require separate logs for performance, audit, etc.
  4. It may require e-mailing details when a log event happens.

Log4J in their varia package has had support for these and more and tested with their APIs. Now with java.util.logging you should be able to download them, but they are not as common knowledge as Log4J and may be harder to find information for.

Another thing to consider is the vendor API you are using. Most vendors "force upon" a logging API for you. Spring is one of them which requires commons-logging.

As a developer, I would try to use java.util.logging if I can for my own stuff, but in real world scenarios you have to shake what they would need in operations and let that drive your choice because they are the ones who have to use these logs when the application goes live. It is neither the application architect nor the developers who should make that choice, though they should make suggestions.

One thing that nobody mentioned in this thread - java.util.logging doesn't support syslog out of the box. Thats a deal-breaker for me, (and has caused me a bit of consternation having to refactor out the java.util.logging stuff in lieu of something with a little more juice.

Here's what I came across today:

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.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top