Hi,

Log4j or any logging framework is very useful entity of any enterprise application, So that we can have a separate Application level logging using our own version of log4j.jar or any other logger framework version.

In this demonstration we will see how to use the log4j logging inside our Web Application, with it’s own version of “log4j.xml” file. We will also talk about the following points:

In this example we will mainly focus on following points

Point-1). How to use the “log4j.xml” which is placed inside “${YOUR_WAR}/WEB-INF/classes” directory.

Point-2). How to avoid using the JBoss provided logging framework or How to exclude the “org.apache.log4j” module provided by JBoss with the help of “${YOUR_WAR}/META-INF/jboss-deployment-structure.xml” file.

Point-3). Where to place your own version of “log4j.jar” file inside your WAR file. “${YOUR_WAR}/WEB-INF/lib”

Point-4). The Source code of this Demo can be downloaded from the following link (Git Repository):
https://github.com/jaysensharma/MiddlewareMagicDemos/tree/master/ApplicationLevelLog4jDemo

Another Demo (uploaded on 26 Nov 2012) at EAR level.
https://github.com/jaysensharma/MiddlewareMagicDemos/tree/master/EAR_Level_Log4jDemo

Developing WAR with it’s own logging

Step-1). Here we are using JBoss AS7.1 Final release latest build “jboss-as-7.1.0.Final” which can be downloaded from the following link: http://www.jboss.org/jbossas/downloads

Step-2). Create a directory with the name “src” somewhere in your file system like “/home/userone/ApplicationLevelLog4jDemo/”. Inside the “src” directory we are going to place our all source code and xml files for development.

Step-3). Write a simple “index.jsp” file inside “/home/userone/ApplicationLevelLog4jDemo/src” as following:

<html>
<head>
<title>Application Level Log4j Demo In JBoss AS7</title>
</head>
<body>

      <form action="TestServlet" method="Get">
           Choose Log Level : 
                           <select name="logLevel">
                              <option>TRACE</option>
                              <option>DEBUG</option>
                              <option>WARN</option>
                              <option selected="true">INFO</option>
                           </select>
                           <BR>
           Enter Mesage to be logged: <input type="textarea" name="logMessage"/> <BR>
           <input type="submit" name="submit" value="log the message"/> 
      </form>
      
</body>
</html>

Step-4). Now we will write a simple Servlet based on Servlet3.0 specification with name “TestServlet.java” inside “/home/userone/ApplicationLevelLog4jDemo/src” as following

package servlets;
import java.io.IOException;
import java.io.PrintWriter;

//servlet-api
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//log4j
import org.apache.log4j.Logger;

@WebServlet(value="/TestServlet")
public class TestServlet extends HttpServlet 
  {
	private static final long serialVersionUID = 1L;
        private static Logger logger = null;

        public void init() throws ServletException {
         logger= Logger.getLogger(TestServlet.class);   
        }

	public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {
			PrintWriter out=response.getWriter();
                        String logLevel=request.getParameter("logLevel");
                        String logMessage=request.getParameter("logMessage");
                        out.println("<html><head><title>Log4j Logging Demo</title></head><body>");
                        if(logLevel.equals("TRACE"))
                           {
                             out.println("["+logLevel+"] "+logMessage+" (logged inside log file).");
                             logger.trace(logMessage);
                           }
                        if(logLevel.equals("DEBUG"))
                           {
                             out.println("["+logLevel+"] "+logMessage+" (logged inside log file).");
                             logger.debug(logMessage);
                           }
                        if(logLevel.equals("INFO"))
                           {
                             out.println("["+logLevel+"] "+logMessage+" (logged inside log file).");
                             logger.info(logMessage);
                           }
                        if(logLevel.equals("WARN"))
                           {
                             out.println("["+logLevel+"] "+logMessage+" (logged inside log file).");
                             logger.warn(logMessage);
                           }

                        out.println("<BR><BR><a href="index.jsp"> Want a different logging level? </a></body></html>");
		     } 
                 catch (Exception e) 
                     {
			e.printStackTrace();
		     }
	}
}

Step-5). The most important part, We will need to write the following kind of “log4j.xml” file inside “/home/userone/ApplicationLevelLog4jDemo/src” as following :

NOTE: We need to just make sure that once the application is build this file should be present inside the ${WAR_NAME}/WEB-INF/classes directory.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
  <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
     <appender name="AppLogAppender" class="org.apache.log4j.DailyRollingFileAppender">
         <param name="DatePattern" value="'.'yyyy-MM-dd"/>
	 <param name="File" value="${jboss.server.log.dir}/MyAppLogsFile.log" />
	 <param name="Append" value="false"/>
         <layout class="org.apache.log4j.PatternLayout">
	     <param name="ConversionPattern" value="%d [%t] %p - %m%n"/>
	 </layout>
     </appender>

     <!-- The "category" represents the package names of your Application APIs which we want to log -->
     <category name="servlets">
         <priority value="TRACE"/>
     </category>

     <root>
         <priority value ="TRACE"/>
         <appender-ref ref="AppLogAppender"/>
     </root>
 </log4j:configuration>

Step-6). Download and place the desired version of log4j jar (like “log4j-1.2.16.jar”) inside the “/home/userone/ApplicationLevelLog4jDemo/src”. So that after building the application this jar will be available inside the “${WAR_NAME}/WEB-INF/lib” directory.

Step-7). Now the most important part, In order to avoid using JBoss provided logging APIs, we need to place the following kind of “jboss-deployment-structure.xml” file inside “/home/userone/ApplicationLevelLog4jDemo/src” so that we can exclude the jboss logging APIs for our application and our application can use it’s own version of logging APIs.

NOTE: after building the WAR file make sure that the “jboss-deployment-structure.xml” is present inside the “META-INF” directory of your WAR file. Example: ${WAR_NAME}/META-INF/jboss-deployment-structure.xml

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
  <deployment>
    <exclusions>
        <module name="org.apache.log4j" />
    </exclusions>
  </deployment>
</jboss-deployment-structure>

NOTE: If you are using JBossAS 7.1.2 then In order to avoid this ClassCastException you will need to include the following System property in your JBoss -Dorg.jboss.as.logging.per-deployment=false
If you are using JBoss AS7.1.2 and not using the above mentioned “jboss-deployment-structure” file then you will see the following kind of exception at the time of deployment of your WAR:

18:05:41,507 ERROR [stderr] (MSC service thread 1-3) log4j:ERROR Could not create an Appender. Reported error follows.
18:05:41,509 ERROR [stderr] (MSC service thread 1-3) java.lang.ClassCastException: org.apache.log4j.DailyRollingFileAppender cannot be cast to org.apache.log4j.Appender
18:05:41,509 ERROR [stderr] (MSC service thread 1-3) 	at org.apache.log4j.xml.DOMConfigurator.parseAppender(DOMConfigurator.java:248)
18:05:41,510 ERROR [stderr] (MSC service thread 1-3) 	at org.apache.log4j.xml.DOMConfigurator.findAppenderByName(DOMConfigurator.java:176)
18:05:41,510 ERROR [stderr] (MSC service thread 1-3) 	at org.apache.log4j.xml.DOMConfigurator.findAppenderByReference(DOMConfigurator.java:191)
18:05:41,510 ERROR [stderr] (MSC service thread 1-3) 	at org.apache.log4j.xml.DOMConfigurator.parseChildrenOfLoggerElement(DOMConfigurator.java:523)
18:05:41,510 ERROR [stderr] (MSC service thread 1-3) 	at org.apache.log4j.xml.DOMConfigurator.parseRoot(DOMConfigurator.java:492)
18:05:41,511 ERROR [stderr] (MSC service thread 1-3) 	at org.apache.log4j.xml.DOMConfigurator.parse(DOMConfigurator.java:1001)
18:05:41,511 ERROR [stderr] (MSC service thread 1-3) 	at org.apache.log4j.xml.DOMConfigurator.doConfigure(DOMConfigurator.java:867)
18:05:41,511 ERROR [stderr] (MSC service thread 1-3) 	at org.apache.log4j.xml.DOMConfigurator.doConfigure(DOMConfigurator.java:794)
18:05:41,512 ERROR [stderr] (MSC service thread 1-3) 	at org.jboss.as.logging.LoggingConfigurationProcessor.deploy(LoggingConfigurationProcessor.java:111)
18:05:41,512 ERROR [stderr] (MSC service thread 1-3) 	at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:116)
18:05:41,513 ERROR [stderr] (MSC service thread 1-3) 	at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1811)
18:05:41,513 ERROR [stderr] (MSC service thread 1-3) 	at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1746)
18:05:41,513 ERROR [stderr] (MSC service thread 1-3) 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
18:05:41,514 ERROR [stderr] (MSC service thread 1-3) 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
18:05:41,514 ERROR [stderr] (MSC service thread 1-3) 	at java.lang.Thread.run(Thread.java:722)

Step-8). Now in order to build and deploy the above application we will write a very simple ant build script “build.xml” inside “/home/userone/jboss-as-7.1.0.Final/standalone/TESTING/ApplicationLevelLog4jDemo” as following:

<project name="Log4j_Basic_Demo" default="deploy">
<property name="jboss.home" value="/home/userone/jboss-as-7.1.0.Final" />
<property name="jboss.module.dir" value="${jboss.home}/modules" />
<property name="basedir" value="." />
<property name="tmp.dir" value="tmp" />
<property name="output.dir" value="build" />
<property name="src.dir" value="src" />
<property name="war.name" value="Log4jDemo.war" />
 
        <path id="jboss.classpath">
             <fileset dir="${jboss.module.dir}">
                 <include name="**/*.jar"/>
             </fileset>
        </path>
 
        <target name="init">
           <delete dir="${output.dir}" />
           <mkdir dir="${output.dir}" />
           <delete dir="${tmp.dir}" />
           <mkdir dir="${tmp.dir}" />
           <mkdir dir="${tmp.dir}/WEB-INF/lib"/>
           <mkdir dir="${tmp.dir}/WEB-INF/classes"/>
           <mkdir dir="${tmp.dir}/WEB-INF/META-INF"/>
           <mkdir dir="${tmp.dir}/META-INF"/>
        </target>
 
        <target name="build" depends="init">
           <javac srcdir="${src.dir}" destdir="${tmp.dir}/WEB-INF/classes"  includes="*.java" classpathref="jboss.classpath" />
           <copy todir="${tmp.dir}/WEB-INF/classes">
                <fileset dir="${src.dir}" includes="**/*.java"/>
           </copy>
           <copy file="${src.dir}/index.jsp" tofile="${tmp.dir}/index.jsp"/>   

           <!-- Make sure to place the "log4j.xml" file inside ${WAR_NAME}/WEB-INF/classes  directory--> 
           <copy file="${src.dir}/log4j.xml" todir="${tmp.dir}/WEB-INF/classes"/>

           <!-- Make sure to place the "log4j-1.2.16.jar" file inside ${WAR_NAME}/WEB-INF/lib  directory--> 
           <copy file="${src.dir}/log4j-1.2.16.jar" todir="${tmp.dir}/WEB-INF/lib"/>

           <!-- Using this file we are going to satisfy the log4j dependency without directly placing the log4j.jar inside "WEB-INF/lib"-->
           <copy file="${src.dir}/jboss-deployment-structure.xml" todir="${tmp.dir}/META-INF"/> 

           <jar jarfile="${tmp.dir}/${war.name}" basedir="${tmp.dir}" compress="true"/> 


           <copy file="${tmp.dir}/${war.name}" tofile="${output.dir}/${war.name}"/>
           <delete includeEmptyDirs="true">
              <fileset dir="${tmp.dir}"/>
           </delete>
        </target>
 
        <target name="deploy" depends="build">
            <echo message="*******************  Deploying the WAR file ${war.name} *********************" />
            <echo message="********** ${output.dir}/${war.name} to ${jboss.home}/standalone/deployments **********" />
            <copy todir="${jboss.home}/standalone/deployments/">
                <fileset dir="${output.dir}/">
                  <include name="${war.name}"/>
                </fileset>
            </copy>
            <echo message="*******************  Deployed Successfully   *********************" />
        </target>
</project>

NOTE: The only change in the above file you need to do is to change the “jboss.home” directory path in the second line of the above script to point to your own JBoss AS7 directory.

Step-9). Now before running your ANT script to build and deploy the above webapplication you should have the ANT as well as JAVA set in the $PATH variable of the Shell / command prompt as following:

For Unix Based OS:
export PATH=/home/userone/jdk1.6.0_21/bin:/home/userone/org.apache.ant_1.6.5/bin:$PATH

For Windows Based OS:
set PATH=C:/jdk1.6.0_21/bin;C:/org.apache.ant_1.6.5/bin;%PATH%

Step-10). Now once the PATH is set In the command/Shell prompt you can move inside the directory “/home/userone/jboss-as-7.1.0.Final/standalone/TESTING/ApplicationLevelLog4jDemo” and then run the ant to build & deploy the webapplication. by running the command “ant deploy”

[userone@localhost ApplicationLevelLog4jDemo]$ ant
Buildfile: build.xml

init:
   [delete] Deleting directory /home/userone/ApplicationLevelLog4jDemo/build
    [mkdir] Created dir: /home/userone/ApplicationLevelLog4jDemo/build
    [mkdir] Created dir: /home/userone/ApplicationLevelLog4jDemo/tmp
    [mkdir] Created dir: /home/userone/ApplicationLevelLog4jDemo/tmp/WEB-INF/lib
    [mkdir] Created dir: /home/userone/ApplicationLevelLog4jDemo/tmp/WEB-INF/classes
    [mkdir] Created dir: /home/userone/ApplicationLevelLog4jDemo/tmp/WEB-INF/META-INF
    [mkdir] Created dir: /home/userone/ApplicationLevelLog4jDemo/tmp/META-INF

build:
    [javac] Compiling 1 source file to /home/userone/ApplicationLevelLog4jDemo/tmp/WEB-INF/classes
     [copy] Copying 1 file to /home/userone/ApplicationLevelLog4jDemo/tmp/WEB-INF/classes
     [copy] Copying 1 file to /home/userone/ApplicationLevelLog4jDemo/tmp
     [copy] Copying 1 file to /home/userone/ApplicationLevelLog4jDemo/tmp/WEB-INF/classes
     [copy] Copying 1 file to /home/userone/ApplicationLevelLog4jDemo/tmp/WEB-INF/lib
     [copy] Copying 1 file to /home/userone/ApplicationLevelLog4jDemo/tmp/META-INF
      [jar] Building jar: /home/userone/ApplicationLevelLog4jDemo/tmp/Log4jDemo.war
     [copy] Copying 1 file to /home/userone/ApplicationLevelLog4jDemo/build

deploy:
     [echo] *******************  Deploying the WAR file Log4jDemo.war *********************
     [echo] ********** build/Log4jDemo.war to /home/userone/jboss-as-7.1.0.Final//standalone/deployments **********
     [copy] Copying 1 file to /home/userone/jboss-as-7.1.0.Final/standalone/deployments
     [echo] *******************  Deployed Successfully   *********************

BUILD SUCCESSFUL
Total time: 2 seconds

Step-11). Now you will able to access your application. “http://localhost:8080/Log4jDemo/index.jsp” try to access the servlet and then check the “${jboss.server.log.dir}/MyAppLogsFile.log” file to see if the application level logging is happening properly.

.
.
Thanks
Middleware Magic Team

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.