Logging APIs - Evaluating Options
In my previous post, I defined a number of different features that logging libraries could have. This time, I will evaluate some Java libraries based on those features. I'll start by ranking these according to how important I think they are, at least for my purposes.
- Severity - mandatory: no logging system should be without this
- Tree of Log Topics - mandatory: no logging system should be without this
- Configurable - vital: configuring log levels at runtime is something we use often
- Rotating Log Files - vital: our log files would be too big for the OS without this
- Configurable Log Line Format - vital: it is unlikely that the off-the-shelf fields would be the ones we want to use
- Logging of Exceptions - vital: getting stack traces from logs is one of our most productive debugging techniques
- Delayed String Construction - vital: I consider this to be an very undervalued feature. Without it, software will be slowed significantly and also will be less readable.
- Log to Multiple Locations - desirable: sometimes this is handy. We used to use it, but at the moment we don't.
- Configure where Logs are Directed - desirable: this, too, we have used in the past but are not using right now.
- Standard or Widely Used - desirable: in the Java world, only Log4J (the most widely used library) and java.util logging (which is in the standard library).
- Unique Messages - desirable: as suggested in the comments, an ability to identify each log usage uniquely (probably by source file and line number) would be handy.
- Sensible Fallbacks - desirable: it's nice that the library works OK when your config fails, because it helps in debugging the config problem.
- Logging Queued to Avoid Delays - nice extra: although this seems like it would be a very useful feature, I do not know of any serious production logging tools that implement it.
- Threadlocal Context Data - nice extra: theoretically, this is extremely useful. In practice, people usually live without it and find the data by reading back through the log.
- Log Filtering - nice extra: if this were easy, we would use it to filter out SSNs and passwords from our logs, but we can live without it.
- Internationalization - undesirable: I recommend against ever using this. Use logging ONLY for developers, NOT for end users; all developers should speak the same language.
Next, I will assemble a list of different logging libraries in Java to be evaluated.
- `Log4J <http://logging.apache.org/log4j/>`__: Log4J by Apache is the most widely used logging framework in Java.
- `Java util logging <http://java.sun.com/javase/6/docs/api/index.html?java/util/logging/package-summary.html>`__: Rather than adopting Log4J as the standard for logging in Java, Sun chose to clone it, creating something almost-but-not-quite the same as a standard Java library.
- `Commons Logging/Log4J <http://commons.apache.org/logging/>`__: Commons Logging is a wrapper from Apache which is designed for use in libraries. It simply delegates to an underlying logging framework. The purpose is so a library can be configured to use the same logging system as the rest of the application. I will consider Commons Logging backed by Log4J.
- `SLF4J/Log4J <http://www.slf4j.org/>`__: SLF4J is a project begun by the original author of Log4J. It is intended to provide a better API for calling into a logging framework, and it can connect to different logging back ends. I will consider SLF4J backed by Log4J.
|Tree of Log Topics||mandatory||Yes||Yes||Yes||Yes|
|Rotating Log Files||vital||Yes||Yes||Yes||Yes|
|Configurable Log Line Format||vital||Yes||Yes||Yes||Yes|
|Logging of Exceptions||vital||Yes||Yes||Yes||Yes|
|Delayed String Construction||vital||No||No||No||Yes|
|Log to Multiple Locations||desirable||Yes||Yes||Yes||Yes|
|Configure where Logs are Directed||desirable||Yes||Yes||Yes||Yes|
|Standard or Widely Used||desirable||Yes||Yes||No||No|
|Logging Queued to Avoid Delays||nice extra||No||No||No||No|
|Threadlocal Context Data||nice extra||Yes||No||No||Yes|
|Log Filtering||nice extra||No||No||No||No|
So, after considering all of these options, I have concluded that my preference is to use SLF4J as an interface, with the implementation from Log4J. Most of the options I have considered have more or less the same features. The deciding factors are (1) Threadlocal storage (MDC) is useful and not present in java.util.logging, and (2) The API for SLF4J provides an elegant solution to delay string construction, which is rather important for performance.
Conveniently, SLF4J publishes a tool for automatically converting existing java.util.logging and Log4J code to SLF4J, so the conversion should be relatively painless.