Question

I have a EAR with structures like:

APP.ear 
- APP1.war
    - WEB-INF/classes/log4j.properties
- APP2.war
    - WEB-INF/classes/log4j.properties
- app1-ejb.jar
- app2-ejb.jar
- log4j.jar
- spring.jar
- commons-lang.jar (...and other jar)

I want each WAR to have their own application log. But it seems the above configuration does not work. Log for APP1 and APP2 goes to APP1's log. Is there anyway to create separate app logs?

Was it helpful?

Solution

It turns out that it's impossible due to the classloader. The classloader hierarchy is like:

Application classloader -> Ejb classloader -> war classloader

To have a sepearte log for individual war, one can put log4j.jar inside war and let the log4j uses the war classloader. But as both app1-ejb.jar and app2-ebj.jar also need to use log4j, the log4j.jar can only be placed at the top level. So the log4j is on application classloader level.

I can specify a single log4j config to log different package to different files. But for the common library like spring, the log cannot be sepearted.

OTHER TIPS

The reason it didnt work because the log4j is present at the root location, instead let each war have a Log4j.jar in its WEB-INF/lib directory and remove the log4j.jar from the root.

For more info on this refer my blog article on this http://techcrawler.wordpress.com/

You can also do that by dynamically changing the FILE property in the properties file using the PropertyConfigurator in code.

Logback is a viable solution to address this problem. After having look around different hacks to make this work with log4j, we have decided to switch to Logback. I have used the following configuration with Logback jar inside the webapp.

A Logback file inside the webapp which include an external file:

    <?xml version="1.0" encoding="UTF-8" ?>
    <configuration scan="true" scanPeriod="10 seconds">
        <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
            <resetJUL>true</resetJUL>
        </contextListener>

        <contextName>${project.artifactId}</contextName>

        <jmxConfigurator />

        <include file="${logback.configuration.filepath}" />
    </configuration>

${logback.configuration.filepath} is replaced during Maven filtering by the exact path, external to the webapp of the configuration file (something like /opt/server/conf/loback.included.conf).

And then, the content of the logback.included.conf (this file is part of the projetct, delivered with build-helper:attach-artifact, so ${project.artifactId} is also replaced during Maven filtering):

    <?xml version="1.0" encoding="UTF-8" ?>
    <included>
        <appender name="file" class="ch.qos.logback.core.FileAppender">
            <file>/var/log/server/${project.artifactId}.log</file>
            <encoder>
                <pattern>[@/%contextName] %date{ISO8601} [%-5level] %thread:[%logger] %msg%n</pattern>
            </encoder>
        </appender>

        <root level="INFO">
            <appender-ref ref="file" />
        </root>
    </included>

Only limitation, the content of the included file must be compliant with the one of the includer. Just writing rules in fact.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top