SeparatingApplicationLogs

Version 28

    Separating Application Logs

    You can segment logging output by assigning log4j categories to specific appenders in

    the conf/log4j.xml configuration. For example, the following

     

       <appender name="App1Log" class="org.apache.log4j.FileAppender">
          <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"></errorHandler>
          <param name="Append" value="false"/>
          <param name="File" value="${jboss.server.home.dir}/log/app1.log"/>
          <layout class="org.apache.log4j.PatternLayout">
             <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
          </layout>
       </appender>
    
    ...
    
       <category name="com.app1">
         <appender-ref ref="App1Log"></appender-ref>
       </category>
       <category name="com.util">
         <appender-ref ref="App1Log"></appender-ref>
       </category>

     

     

    If you have multiple apps with shared classes/categories, and/or want the JBoss categories

    to show up in your app log then this approach will not work. There is a new appender filter

    called TCLFilter (attached) that will be in the 3.2.4 release that can help with this. You

    add the filter to the appender and specify what deployment url should logging be restricted

    to. For example, if your app1 deployment was app1.ear, you would use the following additions

    to the conf/log4j.xml:

     

       <appender name="App1Log" class="org.apache.log4j.FileAppender">
          <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"></errorHandler>
          <param name="Append" value="false"/>
          <param name="File" value="${jboss.server.home.dir}/log/app1.log"/>
          <layout class="org.apache.log4j.PatternLayout">
             <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
          </layout>
          <filter class="org.jboss.logging.filter.TCLFilter">
             <param name="AcceptOnMatch" value="true"/>
             <param name="DeployURL" value="app1.ear"/>
          </filter>
       </appender>
    
    ...
    
       <root>
          <appender-ref ref="CONSOLE"></appender-ref>
          <appender-ref ref="FILE"></appender-ref>
          <appender-ref ref="App1Log"></appender-ref>
       </root>

     

    Update with JBoss Common 1.0.5.GA, 1.2.1.GA, 2.2.1.GA

    (see JBCOMMON-27, JBAS-4413 and ASPATCH-236)

     

    Starting with the above listed jboss-common.jar version, first introduced in JBoss 4.0.5_CP06, it is possible to add multiple TCLFilter definitions to an appender. This way, the logging of several applications can be routed to a single file.

     

    Please note that in order to achieve this, the behavior of the TCLFilter has changed! By default, it will not end the filter chain any more, thus all logging events will also land in the filtered log. To get just the log events of one or more applications in a single log file, it is now necessary to end this chain by appending the DenyAllFilter after the last TCLFilter:

     

       <appender name="App1Log" class="org.apache.log4j.FileAppender">
          <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"></errorHandler>
          <param name="Append" value="false"/>
          <param name="File" value="${jboss.server.home.dir}/log/app1.log"/>
          <layout class="org.apache.log4j.PatternLayout">
             <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
          </layout>
          <filter class="org.jboss.logging.filter.TCLFilter">
             <param name="AcceptOnMatch" value="true"/>
             <param name="DeployURL" value="app1.ear"/>
          </filter>    
      
          <!-- end the filter chain here -->
          <filter class="org.apache.log4j.varia.DenyAllFilter"></filter>
    
       </appender>

     

    JBoss AS 5.1.0

    To enable separate log files under jBoss the following steps are required:

    1. Upgrade the jboss-logging libraries to the 2.1.1 version. You should back up the existing files from <jboss>/lib folder first.
    2. Create an appender definition as described, being sure to use the recently added org.jboss.logging.filter.TCLMCFilter class.

     

    JBoss AS 6.0.0.M1

    For JBoss AS 6.0 M1 the filter class to be used is

     

          <filter class="org.jboss.logging.filter.TCLMCFilter">

     

    Rest of the configurations remain the same. This new org.jboss.logging.filter.TCLMCFilter is available in jboss-logging 2.1.1.GA release

     

    See JBAS-6532, through which this new filter class was introduced.

     

    Post JBoss AS 6.0.0.M1

    Starting with JBoss AS 6.0.0.M2 the ability to log to separate log files, per application, will be implemented in a different way. The TCLFilter/TCLMCFilter will *not* apply there. This section will be updated with more details, once the implementation is ready.

     

     

    Deploy Application as .war File

     

    Note when application is deployed as .war file, it is expanded in a folder under ${jboss.server.home.dir}/tmp/deploy directory name as "tmp-exp.war".

    For example, to configure a filter to archive app1.war, the correct jboss-log4j.xml should be :

     

    <appender name="App1Log" class="org.apache.log4j.FileAppender">
          <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"></errorHandler>
          <param name="Append" value="false"/>
          <param name="File" value="${jboss.server.home.dir}/log/app1.log"/>
          <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %-5p %c{1} %m%n"/>
          </layout>
          <filter class="org.jboss.logging.filter.TCLFilter">
             <param name="AcceptOnMatch" value="true"/>
             <!-- value="app1.war" is incorrect. -->
             <param name="DeployURL" value="app1-exp.war"/>
          </filter>    
      
          <!-- end the filter chain here -->
          <filter class="org.apache.log4j.varia.DenyAllFilter"></filter>
    
       </appender>
       ...
      <root>
          <appender-ref ref="CONSOLE"></appender-ref>
          <appender-ref ref="FILE"></appender-ref>
          <appender-ref ref="App1Log"></appender-ref>
      </root>

    Separating Application Logs - without the monolithic jboss-log4j.xml file


    Alternative A: private log4j library in your WAR/EAR:

    This technique has been confirmed for jboss-eap-4.3 and jboss-4.2.3.GA but will likely work for other versions.

     

    If you want to have split application logs and have that log4j.xml based configuration separated out (e.g.  Not have it all in the jboss-log4j.xml file) then you can do the following.

     

    1.)  Your WAR/EAR must contain log4j-1.2.16.jar.  It must be 1.2.16 or later as earlier versions don't work.

    2.)  The class loading for that WAR or EAR must have its java2ParentDelegation=false.  So for example the jboss-app.xml file will look something like this:

     

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE jboss-app PUBLIC
          "-//JBoss//DTD J2EE Application 1.4//EN"
          "http://www.jboss.org/j2ee/dtd/jboss-app_4_2.dtd">
    <jboss-app>
      <loader-repository>${your domain}:archive=${your app name}.ear
        <loader-repository-config>java2ParentDelegation=false</loader-repository-config>
      </loader-repository>
    </jboss-app>
    

     

    Now this means that the WAR/EAR will use the log4j-1.2.16.jar for logging within its own classloader, i.e.  It will not use Jboss's log4j.jar library or its jboss-log4j.xml file.

     

    3.)  In the MANIFEST.MF file in your WAR/EAR archive you need to set a Class-Path: entry that shows the location (directory) where the log4j.xml file that you want to use will reside.  For example if your EAR file is deployed in the deploy directory, your Class-Path reference might be something like this:

     

    Class-Path: ../conf/log/${application name}/

     

    4.)  Your log4j.xml file should just be an ordinary one, with no references to any special jboss classes.  However, it will have an appender with the specifc name for the log file for the application you want to log for, e.g.

     

    <appender name="${module.name}" class="org.apache.log4j.RollingFileAppender">
        <param name="File" value="${jboss.server.home.dir}/log/${module.name}.log"/>
        <param name="Threshold" value="INFO"/>
        <param name="Append" value="true"/>
        <param name="MaxFileSize" value="2MB"/>
        <param name="MaxBackupIndex" value="20"/>
        <layout class="org.apache.log4j.PatternLayout">
          <param name="ConversionPattern" value="%d{yyyyMMdd HH:mm:ss.SSS} %-5p [%t] %C{1}.%M(): %x %m%n"/>
        </layout>
      </appender>
    

     

    5.)  OPTIONAL:  You can still have all of your logging also go to the shared central $JBOSS_HOME/${instance}/log/server.log file by adding the following to your log4j.xml file:

     

    <appender name="all" class="org.apache.log4j.RollingFileAppender">
        <param name="File" value="${jboss.server.home.dir}/log/server.log"/>
        <param name="Threshold" value="INFO"/>
        <param name="Append" value="true"/>
        <param name="MaxFileSize" value="2MB"/>
        <param name="MaxBackupIndex" value="20"/>
        <layout class="org.apache.log4j.PatternLayout">
          <param name="ConversionPattern" value="%d{yyyyMMdd HH:mm:ss.SSS} %-5p [%t] %C{1}.%M(): %x %m%n"/>
        </layout>
      </appender>
    

     

    Alternative B: Merging log configs:

    This alternative has worked on JBoss 5.1.0 GA. Should work on any other JBoss version - providing it is set up with Log4j as log facility of choice.

    1.) Define a fragment log4j config file and store it in your EAR (e.g. in the ear's root). Be sure not to overwrite config elements of the global jboss-log4j.xml - except you want to do this explicitly. (e.g. turn on logging for Hibernate)

     

    {code:xml}


    <?xml version="1.0" encoding="UTF-8"?>

    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">

      <appender name="srv.FILE" class="org.jboss.logging.appender.DailyRollingFileAppender">


          <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>


          <param name="File" value="${jboss.server.log.dir}/SRV.log"/>


          <param name="Append" value="true"/>


          <layout class="org.apache.log4j.PatternLayout">


             <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>


          </layout>
          <filter class="org.jboss.logging.filter.TCLMCFilter">


             <param name="AcceptOnMatch" value="true"/>

             <param name="DeployURL" value="mySuperApplication.ear"/>
          </filter>
      </appender> 

     


      <logger name="my.package.name" additivity="true">


        <level value="DEBUG" />

     

        <appender-ref ref="srv.FILE" />

     

      </logger>

     

    </log4j:configuration>

    {code}

     

    In our case, we just need an additional appender and our own logger (formerly known as category). set additivity to false if you dont want to appear your private log messages in higher log categories (e.g. jboss server log)

     

    2.) Our app has a service POJO/MBean for adjusting settings via JMX console and provide centralized management of settings for the other beans (SBs and MDBs). In this MBean we define a method, which loads the cfg and merges it into Log4Js global config:

     

    {code}@Service(objectName="SRVService:service=Settings")


    @Management(value=SRVManagementServiceMBean.class)


    public class SRVManagementService implements SRVManagementServiceMBean


    {
    ............


    ..........


    .


      public void updateLogConfig()
      {


        // try to read the local logconfig


        URL logcfgURL=Thread.currentThread().getContextClassLoader().getResource("logconfig.xml");


        if(logcfgURL!=null)


          DOMConfigurator.configure(logcfgURL);


        else


          System.err.println("Private log config not found");


      }


    .........


    ..


    }


    {code}

     

     

    Exposing the update method on the management interface would allow manual updates via JMX console.

    You could also use configureAndWatch(..). Both ways only make sense with mutable config files - which is not the case when you have it in the ear file.

     

    3.) This method must be called as soon as possible during server startup. We chose do do this in the MBeans constructor. Of course you may call it in the container's callback methods start() or startService() as well. I would not use the update Method it in a pooled object, since you would read the config multiple times depending on pool size and object turnover.

     

    4.) All the beans/objects, who would like to log through the private logger should acquire the Logger instance AFTER merging the config. Otherwise you'd get the global logger from the jboss log4j config. Also do not use static Loggers since acquiring the instance happens before merging.

     

    {code:java}

    public class MySessionBeanorMDBean  extends/implements..............

     

    {

       private Logger log=Logger.getLogger(this.getClass());


       ........

     

    .....

     

    }

    {code}

     

     

     

    *Referenced by:*