Channels ▼
RSS

Design

Custom Configuring Java Apps: Extending log4j


Loose Ends

There are a couple more loose ends: First, you'd ideally use ExtendedLogger everywhere you intend to do logging, but you may not have that luxury. A library that you use might use org.apache.log4j.Logger, for example. Since ExtendedLogger just wraps a standard Logger, there aren't any major problems, but the output might not look the way you want it to. For example, if you do this:

    com.holub.util.ExtendedLogger log1 = com.holub.util.ExtendedLogger.getLogger( "loggerName" );
    org.apache.log4j.Logger       log2 = org.apache.log4j.Logger.getLogger( 
                                         "loggerName" );

    log1.debug("hello");
    log2.debug("world");

Then log2 just points at the wrapped logger, the one that's inside the log1 object. The ExtendedLogger will take care of configuration, so the output even looks the same.

Reversing the previous calls actually has no impact. The ExtendedLogger calls the log4j Logger.getLogger() method to get the wrapped logger, so it will get the logger created by the (now) initial call. The output will still reflect the correct configuration file because the ExtendedLogger will have reconfigured log4j before any log() requests are actually made, so you'll get the new configuration.

If the two calls are in different files, however, there's no telling what might happen with the configuration. The ExtendedLogger.getLogger() invocation might be in a class that isn't even loaded when the Logger.getLogger() call and associated log() statement is made. You can call ExtendedLogger.configure() from your main() (if you have one) or your ServletContextListener object, which executes when a Web application first loads, before and servlets are launched. For example:

package com.holub.myServlet;

import javax.servlet.ServletContextEvent;
import javax.servlet.annotation.*;
import com.holub.util.ExtendedLogger;

@WebListener
public class ContextInitializer implements 
javax.servlet.ServletContextListener
{
    public void contextInitialized(ServletContextEvent sce)
    {   
        ExtendedLogger.configure();
    }
    public void contextDestroyed(ServletContextEvent sce){ /*nothing to do*/ }
} 

The @WebListener annotation is new to Tomcat 7, and frees you from having to something like the following into web.xml:

    <listener>
        <listener-class>com.holub.myServlet.contextInitializer</listener-class>
    </listener>

(Other annotations let you do pretty much everything else that you'd do in the XML, so the web.xml file is optional under Tomcat 7.)

Unfortunately, you can never guarantee that a call to ExtendedLogger.configure(), no matter where you put it, will happen at the right time when static initializers are on the scene, so we're back where we started. I usually protect myself from this situation by putting a stock log4j.properties file (that just logs everything to the console) on my classpath, and then expect that configuration to be preempted by the real one once the program is actually running. At least I don't lose logging messages that way, but a few messages might end up in the wrong place.

The final loose end has to do with the "multiple-deployments-of-a-single-app" problem I discussed earlier. Several instances of a given Web application might be running simultaneously (with different names) in a single container, and each of those Web applications might need a different configuration. I usually solve that problem in my ContextInitializer more or less like this:

//...
@WebListener
class ContextInitializer implements javax.servlet.ServletContextListener
{
    @Override public void contextInitialized(ServletContextEvent sce)
    {
        ServletContext context  = sce.getServletContext();
        String applicationPath  = context.getRealPath("/"); 
// root dir of the Web app
 
        if( applicationPath.endsWith("/") ) 
// cut the trailing slash if necessary
            applicationPath = 
              applicationPath.substring(0, applicationPath.length() -1 );
 
        System.setProperty("CONFIG", applicationPath + ".config" );
        Places.reset();
        ExtendedLogger.configure();
    }
 
    @Override public void contextDestroyed(ServletContextEvent sce){
        /* nothing to do */ }
}

The getRealPath() call returns the real path, in the server's file system, to the root directory of the expanded Web application. I lop off a trailing slash if it's there, and replace it with a ".config" suffix. For example, if my application was deployed to /usr/tomcat7/Web apps/myApp, then the resulting string will be /usr/tomcat7/Web apps/myApp.config. I then set the Places.CONFIG directory to that location by modifying the CONFIG system property and resetting the enum (see last month's article). Finally I configure everything. The .config directory must already exist, and have the necessary files in it, of course.

Coming Up

Next month, I'll finish up the topic of configuration by looking at a file-based configuration system.

Related Reading

Solving the Configuration Problem for Java Apps


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video