1 2 3 Previous Next 39 Replies Latest reply: Feb 3, 2013 10:23 AM by Arnab Sarkar RSS

TCLFilter

robert lazarski Newbie

Hi all, I've read the docs and searched the archives but I still have a problem. I have two war's (penguin.war and wtf.war) and I want separate logs for each war. I've added these appenders in jboss-log4j.xml :

<appender name="penguinLog" 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/penguinLog.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"/>
 <param name="DeployURL" value="penguin"/>
 </filter>
 </appender>

 <appender name="wtfLog" 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/wtfLog.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"/>
 <param name="DeployURL" value="wtf"/>
 </filter>
 </appender>
 <root>
 <appender-ref ref="CONSOLE"/>
 <appender-ref ref="FILE"/>
 <appender-ref ref="penguinLog"/>
 <appender-ref ref="wtfLog"/>
 </root>


In case it matters, the war's reside in my dir /programs/deploy via this entry in jboss-5.0.0.GA/server/default/conf/bootstrap/profile-repository.xml :

<property name="applicationURIs">
 <array elementClass="java.net.URI">
 <value>${jboss.server.home.url}deploy</value>
 <value>file:///programs/deploy</value>
 </array>
</property>


The result is that both penguinLog.log and wtfLog.log have the same exact content and file size. If I add:

<filter class="org.apache.log4j.varia.DenyAllFilter"></filter>


To either the penguinLog or wtfLog appenders, then that file size remains zero when jboss starts. Anyone see a problem with my config which prevents separate logs for each of my war's?


  • 1. Re: TCLFilter
    Joao Viragine Newbie

    iksrazal,

    Try to use:

    <param name="DeployURL" value="wtf-exp.war"/>


    note the use of -exp.war as described here: http://www.jboss.org/community/docs/DOC-12203

    Cheers,
    JP

  • 2. Re: TCLFilter
    robert lazarski Newbie

    Hmm, I tried your suggestion and both logs still show the same content and file sizes. Is DOC-12203 updated for JBoss 5 ? I ask because, after running "updatedb" and "locate", there are no files or directories with *exp.war* anywhere on my system. Here's my latest config:

    <appender name="penguinLog" 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/penguinLog.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"/>
     <param name="DeployURL" value="penguin"/>
     </filter>
     </appender>
    
     <appender name="wtfLog" 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/wtfLog.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"/>
     <param name="DeployURL" value="wtf-exp.war"/>
     </filter>
     </appender>
    
     <root>
     <appender-ref ref="CONSOLE"/>
     <appender-ref ref="FILE"/>
     <appender-ref ref="penguinLog"/>
     <appender-ref ref="wtfLog"/>
     </root>
    


    Please help.

  • 3. Re: TCLFilter
    Joao Viragine Newbie

    Sorry, but I didn't test this in JBoss AS 5... :-(
    In AS 4 you can find the exploded archive in ${jboss.server.home.dir}/tmp/deploy

  • 4. Re: TCLFilter
    robert lazarski Newbie

    I created a jira for this issue:

    https://jira.jboss.org/jira/browse/JBAS-6532

  • 5. Re: TCLFilter
    jaikiran pai Master

    Its actually a combination of the code in TCLFilter and the org.jboss.web.tomcat.service.WebCtxLoader's ENCLoader which is causing this issue. The TCLFilter has this piece of code

    /** Start with the current thread context class loader
     * @return true if the caller tcl has a url matching our deployURL
     */
     private boolean isMatchingTCL()
     {
     ClassLoader tcl = Thread.currentThread().getContextClassLoader();
     if( matchSet.contains(tcl) )
     return true;
     if( missSet.contains(tcl) )
     return false;
    
     // Search the class loader URLs for a match
     ClassLoader cl = tcl;
     boolean match = false;
     while( cl != null )
     {
     URL[] urls = getClassLoaderURLs(cl);
     for(int n = 0; n < urls.length; n ++)
     {
     URL u = urls[n];
     String file = u.getFile();
     if( file.indexOf(deployURL) > 0 )
    
    


    And relies on this getClassLoaderURLs method (which relies on reflection) to see whether the current classloader corresponds to the deployURL:

    /** Use reflection to access a URL[] getURLs method so that non-URLClassLoader
     class loaders that support this method can provide info.
     */
     private static URL[] getClassLoaderURLs(ClassLoader cl)
     {
     URL[] urls = {};
     try
     {
     Class returnType = urls.getClass();
     Class[] parameterTypes = {};
     Method getURLs = cl.getClass().getMethod("getURLs", parameterTypes);
     if( returnType.isAssignableFrom(getURLs.getReturnType()) )
     {
     Object[] args = {};
     urls = (URL[]) getURLs.invoke(cl, args);
     }
     if( urls == null || urls.length == 0 )
     {
     getURLs = cl.getClass().getMethod("getClasspath", parameterTypes);
     if( returnType.isAssignableFrom(getURLs.getReturnType()) )
     {
     Object[] args = {};
     urls = (URL[]) getURLs.invoke(cl, args);
     }
     }
     }
     catch(Exception ignore)
     {
     }
     return urls;
     }
    


    The .war application (ex: jmx-console.war) is loaded through the WebCtxLoader's ENCLoader. The ENCLoader has package static access:

    public class WebCtxLoader
     implements Lifecycle, Loader
    {
     private static final Logger log = Logger.getLogger(WebCtxLoader.class);
     /**
     * The ClassLoader used to scope the ENC
     */
     protected ClassLoader encLoader;
    ... // removed irrelevant code intentionally
    ... // removed irrelevant code intentionally
    ... // removed irrelevant code intentionally
    // This won't be accessible to the TCLFilter
     /**
     * A trival extension of URLClassLoader that uses an empty URL[] as its
     * classpath so that all work is delegated to its parent.
     */
     static class ENCLoader extends URLClassLoader
     {
    ... // removed irrelevant code intentionally
     public URL[] getURLs()
     {
     return urllist;
     }
     }
    }
    
    


    and hence is not available through reflection to the TCLFilter. As a result, the filter always has a empty set of URLs and hence the filtering fails.

    Looking at the code in the TCLFilter and the ENCLoader (which extends URLClassloader), i guess the TCLFilter's getClassLoaderURLs(ClassLoader cl) method can be patched to do this:


    /**
     * First check if the cl is of type URLClassloader. If yes, then use the getURLs API without the
     * need for reflection. If its not a URLClassloader type then go for reflection
     * to access a URL[] getURLs method so that non-URLClassLoader
     * class loaders that support this method can provide info.
     */
     private static URL[] getClassLoaderURLs(ClassLoader cl)
     {
     URL[] urls = {};
     try
     {
     // FIrst check the type of cl, if URLClassloader type then don't use reflection
     if (cl instance of URLClassLoader)
     {
     URLClassLoader urlClassLoader = (URLClassLoader) cl;
     urls = urlClassLoader.getURLs();
    
     }
    
     else
     { //let's rely on reflection
     Class returnType = urls.getClass();
     Class[] parameterTypes = {};
     Method getURLs = cl.getClass().getMethod("getURLs", parameterTypes);
     if( returnType.isAssignableFrom(getURLs.getReturnType()) )
     {
     Object[] args = {};
     urls = (URL[]) getURLs.invoke(cl, args);
     }
     if( urls == null || urls.length == 0 )
     {
     getURLs = cl.getClass().getMethod("getClasspath", parameterTypes);
     if( returnType.isAssignableFrom(getURLs.getReturnType()) )
     {
     Object[] args = {};
     urls = (URL[]) getURLs.invoke(cl, args);
     }
     }
     }
     }
     catch(Exception ignore)
     {
     }
     return urls;
     }
    
    


    That should fix the problem. Then your log4j.xml can have this:

    <appender name="App1Log" class="org.apache.log4j.FileAppender">
    ....
     <filter class="org.jboss.logging.filter.TCLFilter">
     <param name="AcceptOnMatch" value="true"/>
     <param name="DeployURL" value="jmx-console.war"/>
     </filter>
    
     <!-- end the filter chain here -->
     <filter class="org.apache.log4j.varia.DenyAllFilter"></filter>
    
     </appender>
    
    
    


  • 6. Re: TCLFilter
    robert lazarski Newbie

    Wow, thanks jaikiran for the patch. I'm running our projects production releases on jboss 5 , so I'm unlikely to be able to test your patch and compile jboss 5 from source. Hopefully the patch gets the attention of the committers and they accept it.

  • 7. Re: TCLFilter
    Mike Wigge Newbie

    Hi all, we've got the same Problem with our JBoss5. I saw that there is a Patch to download on Jira but I don't know how to install it. Can anyone please help me with it?

    Thanks

  • 8. Re: TCLFilter
    jaikiran pai Master

     

    "mwigge" wrote:
    I saw that there is a Patch to download on Jira but I don't know how to install it. Can anyone please help me with it?

    Thanks


    To use the patch, you will have to checkout the common-logging-log4j project trunk from SVN and apply this patch there and then build a jboss-logging-log4j.jar out of it. The jar can then be (re)placed in the %JBOSS_HOME%/lib folder.

    Instead, i think i will build that jar from the patch and attach it to the JIRA. You can then replace it in the %JBOSS_HOME%/lib folder. I would however recommend that you maintain a backup of the existing jar before doing this. And remember, the jar attached to the JIRA is just for convenience and ultimately, the fix will be available after the patched is reviewed and applied in SVN.


  • 9. Re: TCLFilter
    jaikiran pai Master

     

    "jaikiran" wrote:

    Instead, i think i will build that jar from the patch and attach it to the JIRA.


    Done. The JIRA has the jar with the patch.

  • 10. Re: TCLFilter
    Preben Ludviksen Newbie

    Does anybody know a way to get this working on JBoss AS 5.1.0.GA?

    And is there any progress on getting this issue fixed? I would say it's a very important feature to have in production. Like many others, I host multiple projects on each JBoss instance and need a way to provide the correct log to the correct developers.

  • 11. Re: TCLFilter
    Vicky Kak Master

     

    "geofrank" wrote:
    Does anybody know a way to get this working on JBoss AS 5.1.0.GA?

    Give a try to this class
    package org.jboss.logging.filter.jboss5;
    
    
    
    import org.apache.log4j.spi.Filter;
    import org.apache.log4j.spi.LoggingEvent;
    import org.jboss.classloader.spi.base.BaseClassLoader;
    import org.jboss.util.collection.WeakSet;
    
    public class TCLFilter extends Filter {
    
     /** The set of TCLs seen to match DeployURL */
     private WeakSet matchSet = new WeakSet();
    
     /** The set of TCLs seen to not match DeployURL */
     private WeakSet missSet = new WeakSet();
    
     /** The deployment URL string fragment to match against */
     private String deployURL;
    
     /** Whether a match should return ACCEPT or DENY */
     private boolean acceptOnMatch = true;
    
     public boolean isAcceptOnMatch() {
     return acceptOnMatch;
     }
    
     public void setAcceptOnMatch(boolean acceptOnMatch) {
     this.acceptOnMatch = acceptOnMatch;
     }
    
     public String getDeployURL() {
     return deployURL;
     }
    
     public void setDeployURL(String deployURL) {
     this.deployURL = deployURL;
     }
    
     public int decide(LoggingEvent event) {
     int ok = Filter.NEUTRAL;
     if (acceptOnMatch == true) {
     if (isMatchingTCL())
     ok = Filter.ACCEPT;
     } else {
     if (isMatchingTCL())
     ok = Filter.DENY;
     }
     return ok;
     }
    
     /**
     * Start with the current thread context class loader
     *
     * @return true if the caller tcl has a url matching our deployURL
     */
     private boolean isMatchingTCL() {
     ClassLoader tcl = Thread.currentThread().getContextClassLoader();
     if (matchSet.contains(tcl))
     return true;
     if (missSet.contains(tcl))
     return false;
     // Search the class loader URLs for a match
     ClassLoader cl = tcl;
     // JBoss5 specific Deployment ClassLoader type
     BaseClassLoader baseClassLoader = null;
     boolean match = false;
     while (cl != null) {
     if (cl instanceof BaseClassLoader) {
     baseClassLoader = (BaseClassLoader) cl;
     if(baseClassLoader.toString().indexOf(deployURL) > 0){
     System.out.println("JBoss5 specific BaseClassLoader is "+baseClassLoader+" and is matched for "+ deployURL);
     match = true;
     break;
     }
     }
     cl = cl.getParent();
     }
     if (match == true)
     matchSet.add(tcl);
     else
     missSet.add(tcl);
     System.out.println("JBoss5 specific BaseClassLoader is "+baseClassLoader);
     return match;
     }
    }
    


  • 12. Re: TCLFilter
    Ales Justin Master

     

    "vickyk" wrote:

    Give a try to this class
    if(baseClassLoader.toString().indexOf(deployURL) > 0){
    


    Wow, that's one ugly hack. ;-)

    And it actually won't work, as BCL::toString only outputs name.
    What you really wanted to use it toLongString.

    But relying on string to do your dirty work is just too hackish.
    Although original impl is not so far away either :-)
    * http://anonsvn.jboss.org/repos/common/common-logging-log4j/trunk/src/main/java/org/jboss/logging/filter/TCLFilter.java

    Let me try to think of something ...


  • 13. Re: TCLFilter
    jaikiran pai Master

     

    "alesj" wrote:

    Let me try to think of something ...


    It's actually fixed https://jira.jboss.org/jira/browse/JBLOGGING-30. I forgot to create a component upgrade request for Branch_5_x to get a new version of JBoss logging.

  • 14. Re: TCLFilter
    Ales Justin Master

     

    "jaikiran" wrote:

    It's actually fixed https://jira.jboss.org/jira/browse/JBLOGGING-30. I forgot to create a component upgrade request for Branch_5_x to get a new version of JBoss logging.

    Is this the fix?
    * http://anonsvn.jboss.org/repos/common/common-logging-log4j/trunk/src/main/java/org/jboss/logging/filter/TCLFilter.java

    How does this retrieve urls from BaseClassLoader?
    e.g. in non web wrapped ENCLoader (or something similar)
    Or is this just intended for web?


1 2 3 Previous Next