“Do I go for SLF4j or LOG4j or both?” Classic question from my team.

SLF4j has been around for sometime now and has been adopted heavily across. But certain things never get over. Hence I thought of writing down my thoughts as a blog to help others.

Going back to the question; SLF4j or LOG4j ? I think this question itself incorrect. SLF4j and LOG4j focus on different areas and they are meant to do two different things. Its like comparing apples and oranges.

SLF4j is a logging facade. It doesn’t do logging by itself and depends on a logging component like LOG4j, Logback or JLogging. SLF4j is an API designed to give generic access to many logging frameworks. So your log code within the application level remains same but the underlying logging framework can be switched without any kind of actual source code changes.

Once you get used to the syntax of SLF4j, then you don’t need to worry about syntax for other logging frameworks. Another major feature of SLF4j which convinced me to use it over my long time favourite LOG4j, is presence of placeholder, which is represented as {} in code. Placeholder is pretty much same as %s in format() method of String, because it gets substituted by actual string supplied at runtime. This not only reduces the number of string concatenations in your code, but also cost of creating string objects. Since Strings are immutable and they are created in String pool, they consume heap memory and most of the time they are not needed e.g. a String used in DEBUG statement is not needed when your application is running on ERROR level in production.

By using SLF4j, you can defer String creation at the runtime, which means only required Strings will be created. If you have been using LOG4j then you must be already familiar with a workaround of putting debug statement inside if() condition, but SLF4j placeholders are much better than that.

LOG4j Style:

 if (LOGGER.isDebugEnabled()) {
 LOGGER.debug("Initiating Batch Processing... RequestId: " + requestId + ", Region: " + region);
 }

SLF4j Style:

LOGGER.debug("Initiating Batch Processing... RequestId: {}, Region: {}", requestId, region);

You might be thinking what if I have multiple parameters? Well you can either use variable arguments version of log methods or pass them as Object array. It is very convenient and efficient way of logging. Remember, before generating final String for logging the message, this method checks if a particular log level is enabled or not, which not only reduces memory consumption but also CPU time involved in executing those String concatenation instruction in advance. It’s also worth knowing that logging has severe impact on performance of the application, and it’s always advised to have only mandatory logging in production environment.

Code Snippet from org.slf4j.impl.Log4jLoggerAdapter:

 public void debug(String format, Object arg1, Object arg2) {
    if (logger.isDebugEnabled()) {
       FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
       logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
    }
 }

Summary:

  1. SLF4j provides place holder based logging, which improves readability of code by removing checks like isDebugEnabled(), isInfoEnabled() etc.
  2. By using SLF4j logging method, you defer cost of constructing logging messages (String), which is both memory and CPU efficient.
  3. On a side note, less number of strings means less work for Garbage Collector; in turn better throughput and performance!
  4. Using SLF4j in your source will make it independent of any particular logging implementation i.e., no need to manage multiple logging configurations for multiple libraries.

So essentially, SLF4j does not replace LOG4j; they work together, hand in hand. SLF4j removes the dependency on LOG4j from your application and makes it easy to replace it in future with more capable library without any kind of source code changes.

By: Nataraj Srikantaiah

Share

Leave a Reply

Your email address will not be published. Required fields are marked *