Java Util Logging and Log4j Behaviour in Tomcat and WebSphere

Logging is the interface between developers and system admin. Developers need to know how their logging code behave in a server envrionment. Admins need to know how to read logging.properties and log4j.properties, configure them and turn on/off logging. This series inspects how two most common logging methods, Java Util Logging and Log4j, behave in Tomcat and WebSphere.

 

Java Util Logging Behaviour in Java SE



Java Util Logging is part of the JDK starting with version 6, which means that you don't need any jars to use it. This article inspects how Java Util Logging behaves in a Java Standard Edition environment.

1. Default Behaviour with Basic Logging Code

  • Let's Start with Basic Logging Code

In the following java util logging sample code, two loggers are created: the mainLogger com.appinf and a perfSubLogger com.appinf.perf.  This is to help us understand how java util logging organizes loggers in a tree structure.  
public class JavaUtilLoggingSETestNoHandlers {

    static Logger perfSubLogger = null;
    static Logger mainLogger = null;
    static {
        mainLogger = Logger.getLogger("com.appinf");
        perfSubLogger = Logger.getLogger("com.appinf.perf");
    }
    
    public static void main(String[] args) throws IOException {

        final long startTime = System.currentTimeMillis();
        perfSubLogger.logp(Level.INFO, "JavaUtilLoggingSETest", "main", "Enter");
        
        mainLogger.logp(Level.INFO, "JavaUtilLoggingSETest", "main", "Processing ... ");

        final long endTime = System.currentTimeMillis();
        perfSubLogger.logp(Level.INFO, "JavaUtilLoggingSETest","main", "Exit Total time : " + (endTime - startTime) + " ms.");
    }}
  • How does Java Util Logging Behave in a Java Standard Environment


1. By default, Logger.getLogger invokes java.util.logging.LogManager. The logManager reads a configuration file and creates loggers based on defined default behaviour. The configuration file can be specified by -Djava.util.logging.config.file. If not specified, Java uses a default one shipped with the JRE, ($java.home)/lib/logging.properties.

2. The following is defined in the default ($java.home)/lib/logging.properties.
  • handlers= java.util.logging.ConsoleHandler -- by default, everything logs to console.
  • .level= INFO -- default log level.
  • java.util.logging.FileHandler.pattern = %h/java%u.log
    java.util.logging.FileHandler.limit = 50000
    java.util.logging.FileHandler.count = 1
    java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
    -- A FileHandler is defined, but not referenced by default.
3. Because of 1 and 2, under default setting, the logging statements in the sample code will write to the console, and nowhere else.



4. You can modify logging.properties to specify logging levels. You may want to leave the JRE logging.properties alone. Make a seperate copy before you modify it and reference it using -Djava.util.logging.config.file.

com.appinf.level = SEVERE
com.appinf.perf.level = INFO



As you can see, statements logged by com.appinf is ommitted.

2. Customize : Log to application specific log files

If you want to log to a application-specific log file in Java SE, you need to use a FileHandler


static Logger mainLogger = null;
    static Logger perfSubLogger = null;
    static {
        mainLogger = Logger.getLogger("com.appinf");
        perfSubLogger = Logger.getLogger("com.appinf.perf");
        
        try {
            FileHandler fh = new FileHandler("logs" + File.separator
                    + "com.appinf.perf.log", 1024 * 5000, 10, true);
            mainLogger.addHandler(fh);
            
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }



There are several things to note here.
  • If you are not using absolute path, it will use the directory where you run the command. (Under C: directly in my testing case.)
  • Subdirectories have to exist beforehand.
  • Even though you specified a file handler, logs are still written to the console. To disable it, you have to setUseParentHandlers to false.

 
  • By default, logs written to files are in XML format, because as mentioned in 2, even though FileHandler is not used, it defined default formatter for file handlers to be XMLFormatter.
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

<record>
<date>2012-10-15T14:05:56</date>
<millis>1350324356198</millis>
<sequence>1</sequence>
<logger>com.appinf</logger>
<level>INFO</level>
<class>JavaUtilLoggingSETest</class>
<method>main</method>
<thread>10</thread>
<message>Processing ... </message>
</record>

  • To log only to file, not to console, and to log in simple format, add the following statements to the code in 5.
        fh.setFormatter(new SimpleFormatter());
        mainLogger.setUseParentHandlers(false);





Appendix

Default getLogger implementation
private static Logger getLoggerWithRes(String name,
            String resourceBundleName, boolean hasResourceName) {
        LogManager man = LogManager.getLogManager();
        Logger l = null;
        synchronized (man) {
            // Try to find an existing logger with the specified name
            l = man.getLogger(name);
            // If no existing logger with the same name, create a new one
            if (null == l) {
                l = new Logger(name, resourceBundleName);
                man.addLogger(l);
                return l;
            }
        }
        if (hasResourceName) {
            updateResourceBundle(l, resourceBundleName);
        }
        return l;
    }

1 comment:

  1. Thanks for sharing this post! I Iearn many important things from the steps of Java util logging behaves in a Java environment. conference apps for iphone

    ReplyDelete