I am trying to configure a custom layout class to Log4J as described in my previous post. The class uses java.util.regex.Matcher
to identify potential credit card numbers in log messages. It works perfectly in unit tests, also in a minimal web app containing a single servlet. However when I try to deploy it with our app in JBoss, I get the following error:
--- MBEANS THAT ARE THE ROOT CAUSE OF THE PROBLEM ---
ObjectName: jboss.web.deployment:war=MyWebApp-2010_02-SNAPSHOT.war,id=476602902
State: FAILED
Reason: java.lang.LinkageError: java/util/regex/Matcher
I couldn't even find any info on this form of the error - typically LinkageError seems to show up with a "loader constrain violation" message, like in here.
Technical details: we use JBoss 4.2, Java 5, Log4J 1.2.12. We deploy our app in an .ear, which contains (among others) the above mentioned .war file, and the custom layout class in a separate jar file (let's call it Commons). We override the default settings in jboss-log4j.xml
with our own log4j.properties
located in a different folder, which is added to the classpath at startup, and is provided via Sapient's Carbon framework.
Update to @skaffman's answer:
The reason we have a separate log4j.properties file is the scheme propagated by Sapient Carbon. This basically decouples the configuration and data files from the application server environment, so that they are accessible via Carbon's lookup functionality and they can be stored in a directory external to the app server. We inherited this setup, and we hate it because it causes us lots of trouble with deployment, classpath issues etc. since it does not adhere to the JEE conventions. We aim to get rid of it in the long run, but it's gonna take time :-(
Even though the separate log4j.properties file is not best practice, it certainly works. It has been functioning in our app for years, and I could also make it work with a minimalist web app containing a single servlet (not using Sapient Carbon). If log4j.properties is put into the classpath, Log4J reads it properly when the web app is launched, and reconfigures logging accordingly.
Update#2: An interesting finding is that Matcher
is not even used in MyWebApp, only in the Commons module (and another module, in a separate jar). In Commons, it has been used before, in a class called StringHelper, which is used indirectly by MyWebApp, via other modules.
I guess this rules out the possibility of two different Matcher class versions loaded by different classloaders. So my only remaining guess is that Matcher is loaded by two different classloaders when it is used from the jar and the war, and then attempted to pass from one to the other. This is explained by Frank Kieviet's excellent article. However, I believe that such a setup would cause a "loader constraint violation" rather than this form of the error.
Update#3: If I add this appender (example 3.8) to jboss-log4j.xml, the error disappears, and the server runs perfectly :-o This obviously has to do something with loading log4j.jar, because this setup requires the jar to be present in the server lib directory. It works also if I change the appender type to org.jboss.logging.appender.FileAppender
, and set log level to WARN
, which results in an empty ucl.log
file. This may suit as a temporary workaround, but I am still eager to fully understand what's going on here.
What does this error message mean, and how can I fix it properly?
Epilogue
After a long wait, I finally got to eliminate Carbon from the logging process and migrate our logging config into server/conf/jboss-log4j.xml
. This required that I publish our custom log filter class in a separate jar in the server/lib
directory. After this, the class loading works again, without the workaround described in Update#3 above :-)