February 08, 2011

Using logging in Java libraries

While logging can be very useful in an application, it's still a question to me whether it is desirable to use logging statements in a library. If the library is well-designed, is there a need for logging? Is it not up to the application to log what seems relevant to it?

Use cases for logging

There are use cases for logging events in your application, including performance logging of audit logs. These can be seen as the implementation of functional requirements, and are typically implemented using AOP. The application signals some sort of an event, and one implementation could be to simply write out the event in a logfile. But these kinds of logging are hardly ever implemented in libraries, as they are the result of functional requirements.

Another typical case of logging is error handling. But a well-designed library should signal the application using the library something is wrong, and let the application decide what to do when an error occurs. Often this involves at least logging it, once and only once by the way!


So why include logging in a library? It might be useful if it's a closed source library you can't easily debug. But for open source libraries using a debugger is the way to go if you want to know what's going on.


Logging in a library

If a library has logging in it anyway, how should it be implemented ideally? There are some useful tips listed in the dark art of logging about what and how to log in general, but there's more...

In a library, please think about the logging library dependency. When writing code, an important part of controlling dependencies is by depending on interfaces instead of implementations. So when depending on a logging library, please just depend on an interface or facade (such as slf4j) instead of an implementation (such as log4j). A single dependency on e.g. slf4j-api would be sufficient, let the application using the library decide which implementation it wishes to use.

Unfortunately there are still a lot of libraries out there depending on commons-logging, log4j or other implementations. Using these libraries in an application involves a process of excluding the logging dependencies and including the slf4j bridging implementations, e.g. using the Maven dependency management. This way the applications and its libraries all log via the slf4j-api, and a single logging implementation can be chosen by the application or the environment it is deployed on (OSGi container anyone?).

Using log4j
Finally a special note to the log4j adepts out there. If you insist on using log4j in your library, try to avoid depending on the log4j appenders and filters, or use the PropertyConfigurator. Doing so makes it impossible to use the slf4j bridging.

It's also not a good idea to include a log4j.properties file in your library jar. Since log4j looks for a config file on the classpath, this config file might get to be used for the entire application although the application adds a config file itself to the classpath. In that case it's a matter of who comes first on the classpath, which might lead to unexpected logging behavior that is really hard to figure out.

It is in fact a tip if you're using log4j and your application logging don't seem to use your own log4j.properties: search the classpath, including third-party jars, for other config files.

6 comments:

  1. Logging is indeed very important and using correct level of logging for a messages is an art. I have seen either excessive logging or no logging which is not great. specially if you are writing sever application then its becomes increasingly important to write important information in log.

    Thanks
    Javin
    How to detect deadlock in java

    ReplyDelete
  2. Moreover the RollingFileAppender is great to use. In one of my project, we were logging application level events in different files based on categories like Info,Debug and Error logs were redirected to different files.

    http://extreme-java.blogspot.com

    ReplyDelete
  3. Async logging is also worth mentioning. Logging DOES have some impact on performance (which may be important in some situations).

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. Having logging in libraries (ideally using SLF4J) can be hugely helpful. Turning on debug level for certain dependencies, for example Spring or httpcomponents, serves to remove the "magic" or black-box character 3rd-party dependencies might otherwise have.

    Also, in case of FOSS, it helps in finding out if a some problem is caused by a bug or misunderstanding in your own code or in the 3rd-party-code. If it's actually located in the 3rd-party code it enables you to actually fix it.

    I guess I haven't started a debugger in the last two years. I can live perfectly well by just using unit tests and logging. ;)

    And, finally, a shameless plug:
    Check out http://lilith.huxhorn.de - it's the logging event viewer I wrote for use with Logback but by now it's also able to handle log4j and java.util.logging events.

    Cheers,
    Joern.

    ReplyDelete
  6. I agreed with the use of SLF4J.
    For example, google app engine logging is only compatible with java logging, so with SLF4j you can switch from log4j to java logging easy.
    those libraries that use an implementation of logging fail in this case

    ReplyDelete