Wednesday, April 11, 2012

How to use 'Apache Commons Logging' with 'Java SE Logging'?


In my previous post I described scenarios when you should consider using Apache Commons-Logging. I also talked briefly about the next step once you decide using Commons-Logging. I had chosen Java SE Logging (as log implementation) and briefly described why I chose it.

Having chosen Commons Logging with JDK logger, I searched for some good examples on internet for this combo. Surprisingly I couldn't find anything good. I even didn't find many samples on Java SE Logging. It seems not many people like Java SE Logging. Why so? I will briefly provide the reasons why.

Getting down to the business: Here are the steps for using Apache Commons Logging with Java SE Logging.

Step 1: Configure Commons-Logging

Put "commons-logging.properties" file in your application's classpath. The contents of this file should look like:
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger
Setting this property instructs Commons-Logging to use JDK Logger (i.e. Java SE Logger) as the Log implementation.

Step 2: Configure Java SE Logger

We need to configure the behavior of Java SE logger as per our requirement. Although JavaSE Logging API offers both Static (from Properties file) and Dynamic (programmatic) configuration, we will need to use Static way. That is because we are using it along with Commons Logging. 
So, it doesn't make sense to programmatically configure the behavior of Java SE logger as it will introduce tight coupling of our code with Java SE Logging API.

My log-config.properties looks like this:
# The following creates two handlers
handlers=java.util.logging.ConsoleHandler, java.util.logging.FileHandler

# Set the default logging level for the root logger
.level=SEVERE
# log level for the "com.rst.example" package
com.rst.example.level=FINE

# Set the default logging level
java.util.logging.ConsoleHandler.level=ALL
java.util.logging.FileHandler.level=FINE

# Set the default formatter
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter

# Specify the location and name of the log file
java.util.logging.FileHandler.pattern=D:/temp/log/log-test.log

Step 3: Start Logging!
Start using the logger in your code as shown in the below sample application:
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class TestLog {

    private static Log log = LogFactory.getLog(TestLog.class);
    public static void main(String[] args) {
        log.info("Testing Info Message.");
        if (log.isDebugEnabled()) {
            log.debug("Testing Debug Message.");
        }
    }
}

Run this program as shown below:
java -Djava.util.logging.config.file=d:\rushikesh\temp\log-config.properties TestLog

You should see the below output on your 'command prompt' as well as your 'log file'.
Apr 12, 2012 3:09:27 PM TestLog main
INFO: Testing Info Message.
Apr 12, 2012 3:09:27 PM TestLog main
FINE: Testing Debug Message.


Bingo! You are done. See how simple it is to use Apache Commons with Java SE logging? You can similarly use Commons Logging with other Logging Frameworks.

Important: 
If you don't set the environment property ('java.util.logging.config.file') 
then you will only see CONSOLE logs as per the default behavior of JavaSE Logger. 
By default it does NOT print debug logs. So you won't see the FINE message.

Here are some practical tips while using Logging in your program:
  • Best Practice: Check if the Log Level is enabled before writing the actual cog statement.
    • Example:  Use "if (log.isDebugEnabled())" before calling "log.debug()"
  • Log level can be configured per package:
    • Example: 'com.rst.example.level=FINE' will set Log level of 'com.rst.example' package to 'FINE' (i.e. debug).
Now, as I mentioned earlier, some people don't like using JavaSE logging. Here are some the Major reasons:
  • Unclear Log levels (FINE, FINER, FINEST, INFO, CONFIG, WARNING, SEVERE)
    • No 'ERROR' level. Use either SEVERE or WARNING.
  • Log properties are global for a Java process. So you cannot package your log configuration properties file in your webapp.
  • There is No way your log configuration can be picked up automatically from the classpath.
  • Visit links provided in 'References' section below for a detailed list/discussion on this.


References:

5 comments:

Anonymous said...

Isn't Apache Commons dependent on older version of JDK? Will this work with v1.6 without any errors?

Rushikesh S. Thakkar said...

Apache Commons has a many components - including logging. AFAIK all of them support JDK 1.4 and higher. In fact, I myself have used Commons Logging with JavaSE 6.

Rushikesh S. Thakkar said...

My post is referred on Stackoverflow: http://stackoverflow.com/a/14510876/2335032

Alex said...

Thanks for the post. How can I configure java logging without the need for a properties file on disk? I don't have access to disk. I could set environment variables or add something to the classpath.

Rushikesh S. Thakkar said...

Thanks Alex,
I haven't tried this myself, but set either 'org.apache.commons.logging.Log' or 'org.apache.commons.logging.LogFactory' environment property to set your choice of logger.