Steven Boscarine wrote:
In porting a large legacy application, we're having issues getting Commons Logging to return a log4j log factory
What's that real issue?
Okay, I found some context to your question. So you are trying to do:
and it's always returning an instance of org.apache.commons.logging.impl.SLF4JLocationAwareLog. Instead what you want is commons logging to use Log4j's LogFactory implementation.
It should be doable once you understand how auto/implicit dependencies (added by the server) are setup on your deployment. The logging dependencies that are added to the deployment, by the server are these:
private static ModuleIdentifier JBOSS_LOGGING = ModuleIdentifier.create("org.jboss.logging"); ... private static ModuleIdentifier COMMONS_LOGGING = ModuleIdentifier.create("org.apache.commons.logging"); private static ModuleIdentifier LOG4J = ModuleIdentifier.create("org.apache.log4j"); private static ModuleIdentifier SLF4J = ModuleIdentifier.create("org.slf4j"); private static ModuleIdentifier JUL_TO_SLF4J = ModuleIdentifier.create("org.jboss.logging.jul-to-slf4j-stub");
So what you need to do is to exclude the relevant dependencies from that set using the jboss-deployment-structure.xml in your deployment. Something like:
<jboss-deployment-structure> <deployment> <!-- Exclude relevant logging dependencies --> <exclusions> <module name="org.slf4j" /> <module name="org.apache.commons.logging" /> </exclusions> </deployment> </jboss-deployment-structure>
(If your top level deployment has nested sub-deployments then make sure you repeat those exlusions under a <sub-deployment> element too so that those are excluded for the sub deployments too).
Notice that we have excluded the org.apache.commons.logging module from the deployment. Although it might seem weird to exclude it, since your application wants to use the commons logging API, it is important to exclude it in this specific case because, this is how the module.xml of org.apache.commons.logging module looks like:
<module-alias xmlns="urn:jboss:module:1.1" name="org.apache.commons.logging" target-name="org.slf4j.jcl-over-slf4j"/>
As you can see the org.apache.commons.logging module is acting as an alias for the org.slf4j.jcl-over-slf4j module. The org.slf4j.jcl-over-slf4j has it's own custom implementation of org.apache.commons.logging.LogFactory and as mentioned in its javadoc http://www.slf4j.org/apidocs/org/apache/commons/logging/LogFactory.html:
Factory for creating Log instances, which always delegates to an instance of SLF4JLogFactory.
So it's no wonder that the Log4j's LogFactory implementation isn't being used in your case.
So getting back to the solution, the first part is to add that jboss-deployment-structure.xml with the relevant module exclusions *and* package the org.apache.commons.logging JAR (which you can download from the apcahe commons project page) within your application. That way, when you use the org.apache.commons.logging.LogFactory class, it's loaded from the JAR packaged in your application and not the SLF4J one which always returns the SLF4JLogFactory.
I haven't tested this myself so not sure if you'll run into some other problems. But give it a try and see if it works.
I think my issue was that we are using an ear and I didn't define jboss-deployment-structure correctly.
Late last night, I realized our issue was that jboss-deployment-structure.xml requires each war to exclude sl4j and commons logging as well.
<?xml version="1.0" encoding="UTF-8"?> <jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2"> <!-- This is how we expose global modules to our application. --> <!-- Remember: EAP6 uses a modular classloader, which means that server libs are isolated from your libs until you specify otherwise as we're doing below --> <deployment> <exclude-subsystems> <!-- We bundle CXF since it is a legacy applicaiton --> <subsystem name="webservices" /> </exclude-subsystems> <dependencies> <!-- Expose JCA Adapter to get to oracle.jdbc.OracleConnection from java.sql.Connection --> <module name="org.jboss.ironjacamar.jdbcadapters" export="true" /> <!-- Expose Global JDBC Driver we installed to get to oracle.jdbc.OracleConnection class itself --> <module name="com.oracle.jdbc" export="true" /> </dependencies> <!-- This appears to be completely ignored --> <exclusions> <module name="org.slf4j" /> <module name="org.slf4j.impl" /> <module name="org.slf4j.jcl-over-slf4j" /> <module name="org.apache.commons.logging" /> </exclusions> </deployment> <!--This is what I was missing --> <sub-deployment name="mywar1.war"> <exclusions> <module name="org.slf4j" /> <module name="org.slf4j.impl" /> <module name="org.slf4j.jcl-over-slf4j" /> <module name="org.apache.commons.logging" /> </exclusions> </sub-deployment> <sub-deployment name="mywar2.war"> <exclusions> <module name="org.slf4j" /> <module name="org.slf4j.impl" /> <module name="org.slf4j.jcl-over-slf4j" /> <module name="org.apache.commons.logging" /> </exclusions> </sub-deployment> <sub-deployment name="mywar3.war"> <exclusions> <module name="org.slf4j" /> <module name="org.slf4j.impl" /> <module name="org.slf4j.jcl-over-slf4j" /> <module name="org.apache.commons.logging" /> <!-- <module name="org.apache.log4j" /> --> </exclusions> </sub-deployment> <!-- Repeat for all 10 of my wars --> </jboss-deployment-structure>
I was excluded modules in the precise place where I was successfully including them, but that wasn't working. I was also a bit surprised that commons logging is exported automatically as I imagine that breaks everyone's logging settings from previous versions.
Once I excluded commons logging on each war, I was able to get my commons-logging.properties to work and therefore could use log4j instead of sl4j.