Jboss logging to slf4j/log4j2 with Keycloak - java

I have a Keycloak EAR module, deployed on Keycloak 11.0. In my EAR module I want to use log4j2 logging library with slf4j. I successfully accomplished this by adding the following dependencies in the pom directly: log4j-slf4j-impl, log4j-api & log4j-core.
Wildfly logging dependencies are excluded by setting add-logging-api-dependencies to false. log4j2.xml is specified outside the packaged EAR and is referenced with log4j.configurationFile system property.
Now the problem. I also want Keycloak to use log4j2 but I cannot get this to work. Keycloak is using Jboss Logging wrapper which always picks up JbossLogManager no matter which logging provider I set - I always get either ClassNotFoundException or NoClassDefFoundError.
I realize there is a classpath problem but I am out of ideas at this point. I tried creating log4j-slf4j-impl, log4j-api & log4j-core Wildfly modules with the following command but I still get the same error.
./jboss-cli.sh --command="module add --name=org.apache.logging.log4j.log4j-api --resources=/Users/jernej/log4j-api-2.13.3.jar"
If I understand correctly, log4j2 should be in the classpath on Wildfly startup (when searching for LoggerProvider) and Jboss Logging findProvider method should return Log4j2LoggerProvider if modules are correctly added? How can I accomplished this?
Suppose I want to use log4j2 appender, located in separate library. If I add this library as a Wildfly module this log4j2 appender can then be used by other deployments as well - e.g. keycloak-server.war?

Adding a library as a module may not necessary makes it available to your application. Have you defined the dependency to that module in the jboss-deployment-structure.xml in the META-INF folder of your ear file? Something like this:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:jboss:deployment-structure:1.3 http://www.jboss.org/schema/jbossas/jboss-deployment-structure-1_3.xsd">
<deployment>
<dependencies>
<module name="org.apache.logging.log4j.log4j-api" export="true"/>
</dependencies>
</deployment>
</jboss-deployment-structure>

Related

Why is the WildFly console log hijacking my WAR's log4j log?

I have 7 different WARs deployed to the same WildFly / JBoss server. Each WAR is identical in core design and Log4j configuration. Each WAR generates its own log file via its own individual custom log4j.xml. Each log is written to an individual folders.
1 of the 7 deployed WARs keeps getting the logging hijacked by WildFly's console.log. It will begin writing to its own log for 5-10 lines during initialization, then stop; the rest of the logging will be directed to the console.log.
If I re-install the WAR after this happens, it will write to both its own individual log and the WildFly console.log. If I restart WildFly, it will behave as described previously - begin logging to its own log, then continue on console.log.
The only thing unique about this WAR vs the other 6 is that this project uses JAXB; none of the other WARs use JAXB.
Is there some sort of unknown interaction between JAXB and Log4j and WildFly that might be causing this? I suspect, but cannot yet prove, the hijack is happening after the classes using JAXB are loaded by the ClassLoader.
jboss-7.2.0.Final , jdk-7u80x64, Log4j-1.2.13.jar
You may need to try move the logging.properties file to the WAR/WEB-INF/classes. I guess old Jboss EAP 6.4, There may have been a bug where it fails to look in the WAR/WEB-INF directory.
If that doesn't work you have to turn on trace logging for org.jboss.as.logging which should show the logging.properties file is found in your deployment.
The following CLI command will enable trace logging to see the details of what the logging subsystem is doing.
/subsystem=logging/logger=org.jboss.as.logging:add(level=TRACE)
If you want to see these log messages on the console you'll need to enable trace logging for the console tool.
/subsystem=logging/console-handler=CONSOLE:write-attribute(name=level, value=TRACE)
resources:
sect-per-deployment_logging
Logging Configuration
Solved by excluding the log4j module from the application via /WEB-INF/jboss-deployment-structure.xml
<jboss-deployment-structure>
<deployment>
<exclusions>
<module name="org.apache.log4j" />
</exclusions>
</deployment>
</jboss-deployment-structure>

Jackson 2 annotations ignored in EJB Jar with JBoss (6.2.0 GA)

I am migrating a web app from Websphere 7 (JEE5) to JBoss EAP 6.2.0 (JEE6). It currently works fine in Glassfish 3 & WAS.
The web interface consumes/produces JSON - so am using Jackson2 with Spring 3 MVC MappingJackson2HttpMessageConverter to handling (de)serialisation in a simple controller class.
In JBoss I see Jackson2 annotations #JsonProperty etc are being ignored in the ejb module - (they are applied to JPA entities only), but are being applied in the web module. So responses come back with different field names for some objects in JBoss which trips up our user interface.
I've tried every permuation of jboss-deployment-structure.xml to no avail (see below). I'm aware that JBoss ships with Jackson 1.x as an internal module. However, this doesn't seem to be the problem, otherwise the web module annotations would be ignored as well ? E.g.: Jackson annotations ignored after deployment to JBOSS
The app is structured as 3 maven modules - war, ejb (jar) & the ear container.
I'm going to refactor the code to remove the annotations from the JPA entities, but really it would be good to find a coherent solution, as there are several other apps to migrate.
JBoss descriptor I've tried below, makes no difference.
<jboss-deployment-structure>
<ear-subdeployments-isolated>false</ear-subdeployments-isolated>
<deployment>
<exclusions>
<module name="org.codehaus.jackson.jackson-core-asl"/>
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
</exclusions>
</deployment>
<sub-deployment name="my-war.war">
<exclusions>
<module name="org.codehaus.jackson.jackson-core-asl"/>
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
</exclusions>
</sub-deployment>
<sub-deployment name="my-ejbs.jar">
<exclusions>
<module name="org.codehaus.jackson.jackson-core-asl"/>
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
</exclusions>
</sub-deployment>
</jboss-deployment-structure>
Initial Workaround (reverted now)
Whilst it does not address what the original problem was caused by, I have solved this by adding a Jackson Mixin within the web module to rename/suppress the fields concerned. I've tested this and it works fine.
The point about all this, is that by using a Jackson Mixin, the scope of the customisation of the serialisation has been confined to the web module, and thereby avoided possible class loading issues due to ejb-jar sub-deployment. No jboss-deployment-structure.xml is being used.
Add a Mixin
public interface MyMixin {
#JsonIgnore
String getUnwantedField();
#JsonProperty(value = "newName")
String getOldName();
}
Then in the startup of my web controller I wire in the Mixin to the Jackson ObjectMapper which is autowired into the controller and defined in my dispatcher servlet xml config.
#Autowired
private ObjectMapper objectMapper;
#PostConstruct
void configObjectMapper() {
objectMapper.addMixInAnnotations(MyEjbJar.class, MyMixin.class);
}
Dispatcher servlet:
.
.
<bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper"/>
I have tracked this down (via IDE debugger & adding logging) to different classloaders being used for the war module and ejb jar module. This is expected default behaviour with JBoss AS 7 according to the docs. The war uses the war ModuleLoader, and the ejb jar uses the ear ModuleLoader.
What happens is the Class for the annotation differs depending on which class loader loads the annotation. Also see: similar issue on SO
By "differs" I mean they are the same annotation, sourced from the same jar & version, but they are not deemed equivalent according to the contract for equals, their hashcodes differ, therefore the JacksonAnnotationIntrospector does not locate annotations even though they show as held against the JPA POJO class.
Workaround
I have worked around this by making the ear ModuleLoader be a common loader for jackson 2. I did this by making the com.fasterxml.jackson.core databind dependency provided scope in the war & ejb jar, and marking it as a normal compile scope dependency in the ear POM.
This kind of approach is sort of endorsed here JBoss AS classloading although it uses the jboss-deployment-structure or MANIFEST.MF to achieve pretty much the same thing.

WildFly AS 8.0 Error: org.hibernate.integrator.spi.Integrator: Provider org.hibernate.envers.event.EnversIntegrator not a subtype

I come from a heavy .NET/IIS background and although I have worked with Java in the past, I am fairly new to large Java web applications so please bear with me. Due to my limited background, I will walk through the steps I took from the very start trying to get this app to deploy (in case my "fix" for another issue could have broken something else).
I am having trouble deploying a Spring/Hibernate application to the WildFly application server. The application itself definitely works because it is a sample project in an open-source eCommerce framework (Broadleaf Commerce). I have also successfully got it to run on Jetty locally.
The application uses three JNDI data sources which I have configured in WildFly/JBoss; I have confirmed that the application sees them because I tried running it prior to configuring the DS's and it gave a clear error, which it no longer did after I configured them.
Afterwards, the application would throw three different errors (one per each PU) saying that it was unable to start the persistence units due to a class loading exception. This error I was able to fix by adding a jboss-deployment-structure.xml file into WEB-INF with the following contents (based on what I understand, this file is needed because this app has all of the Hibernate JARs within its WAR file already, and thus the below file tells JBoss not to supply its own Hibernate implementation):
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
<deployment>
<exclusions>
<module name="org.hibernate"/>
<module name="org.javassist"/>
<module name="org.apache.log4j" />
</exclusions>
<dependencies>
<module name="org.jboss.ironjacamar.jdbcadapters" slot="main"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
After adding the above file, I now get this set of three (one per each PU) errors:
23:15:16,791 INFO [org.jboss.as.controller] (DeploymentScanner-threads - 2) JBAS014774: Service status report
JBAS014777: Services which failed to start: service jboss.persistenceunit."admin.war#blPU".__FIRST_PHASE__: org.jboss.msc.service.StartException in service jboss.persistenceunit."admin.war#blPU".__FIRST_PHASE__: java.util.ServiceConfigurationError: org.hibernate.integrator.spi.Integrator: Provider org.hibernate.envers.event.EnversIntegrator not a subtype
service jboss.persistenceunit."admin.war#blSecurePU".__FIRST_PHASE__: org.jboss.msc.service.StartException in service jboss.persistenceunit."admin.war#blSecurePU".__FIRST_PHASE__: java.util.ServiceConfigurationError: org.hibernate.integrator.spi.Integrator: Provider org.hibernate.envers.event.EnversIntegrator not a subtype
service jboss.persistenceunit."admin.war#blCMSStorage".__FIRST_PHASE__: org.jboss.msc.service.StartException in service jboss.persistenceunit."admin.war#blCMSStorage".__FIRST_PHASE__: java.util.ServiceConfigurationError: org.hibernate.integrator.spi.Integrator: Provider org.hibernate.envers.event.EnversIntegrator not a subtype
There is a file called hibernate-envers-4.1.11.Final.jar inside the WAR archive. Also remember that this is the same WAR (except the jboss-deployment-structure.xml file) which ran successfully on Jetty.
I tried poking around but simply have no idea where to look... I tried changing the DS's in WildFly to use a JDBC4-based driver as well as a JDBC41 (probably has nothing to do with it) with no luck. I know it is probably something very simple and is related to configuration (of either WildFly or the application itself), but I am not sure where to poke around.
My completely out of the blue take on it is that WildFly is still somehow trying to load an older version of Hibernate, which the classes in the bundled 4.1.11 Envers JAR are trying to override but cannot (or vice versa).
If it is of any use - the app is trying to connect to a PostgreSQL 9.3 database and the DS's defined in WildFly work as far as clicking "Test Connection" goes.
If there is any other info I can provide which would be helpful, please let me know.
Any insights or hints would be very much appreciated.
The Wildfly server has a Hibernate 4.3 version. To use Hibernate 4.1 you have to exclude the default Hibernate and package the correct one.
Class Loading in WildFly
Example:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
<exclusions>
<module name="org.hibernate" />
<module name="org.hibernate.envers" />
<module name="org.hibernate.validator" />
<module name="org.hibernate.commons-annotations" />
</exclusions>
</deployment>
</jboss-deployment-structure>
I never figured out the cause of the issue (but I am figuring it was a conflict with the JARs supplied by JBoss).
Just in case anyone is having the same issue - I ended up using Tomcat where everything worked without a hitch. I understand this isn't exactly a solution but it will work in the interim. This also possibly reinforces my initial suspicion of the JARs provided by JBoss conflicting with the bundled Hibernate JARs in the project.

OpenCV as JBoss-as global module

Problem presentation
I try to install OpenCV as global module of a JBoss-as instance. The versions are:
JBoss-as: 7.1.1 Final
OpenCV: 2.4.5 (compiled with Java support)
I started from a fresh installation of Ubuntu Server 12.04 64 bits with only JBoss-as and OpenCV installed.
Preamble
The OpenCV java wrapper use JNI calls. Thus two things are required:
opencv-245.jar
libopencv_java245.so
And available in /usr/share/OpenCV/java/ (regarding to installation)
I also point some observations:
The installation of JBoss is correct (applications can be deployed and are working)
The compilation and installation of OpenCV with java support is correct (Java class using OpenCV are working)
A basic web application using OpenCV and deployed, with maven, on JBoss-as works (the opencv-245.jar is listed as dependency in pom.xml, and thus packaged into the war)
Problem description
As soon as I define OpenCV as JBoss global module (setting <scope>provided</scope> in pom.xml) this exception is raised:
java.lang.UnsatisfiedLinkError: org.opencv.core.Mat.n_Mat()J
org.opencv.core.Mat.n_Mat(Native Method)
org.opencv.core.Mat.<init>(Mat.java:441)
WS.printMessage(WS.java:15)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:616)
org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:155)
org.jboss.resteasy.core.ResourceMethod.invokeOnTarget(ResourceMethod.java:257)
org.jboss.resteasy.core.ResourceMethod.invoke(ResourceMethod.java:222)
org.jboss.resteasy.core.ResourceMethod.invoke(ResourceMethod.java:211)
org.jboss.resteasy.core.SynchronousDispatcher.getResponse(SynchronousDispatcher.java:525)
org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:502)
org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:119)
org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:208)
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:55)
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:50)
javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
It appears that the OpenCV jar library is found because the exception is raised from it. Also it does not complains about some library not found like (taken from first link at the end):
java.lang.UnsatisfiedLinkError: no xxxx in java.library.path
thus I guess the libopencv_java245.so is not the problem. The precise configuration is described below.
Configurations
I defined the org.opencv module in modules/org/opencv/main/module.xml:
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="org.opencv">
<resources>
<resource-root path="opencv-245.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
</dependencies>
</module>
Then I put in the same folder opencv-245.jar and also libopencv_java245.so in lib/linux-x86_64/ subfolder (as explained in Native Library)
To define this module as global I modified in standalone/configuration/standalone.xml:
<subsystem xmlns="urn:jboss:domain:ee:1.0">
<global-modules>
<module name="org.opencv" slot="main"/>
</global-modules>
</subsystem>
Finally to use the global module I set in src/main/webapp/WEB-INF/jboss-deployment-structure.xml:
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.opencv" />
</dependencies>
</deployment>
</jboss-deployment-structure>
I also reminds that I have put <scope>provided</scope> in my maven pom.xml.
Also, putting:
System.loadLibrary("opencv_java245");
or not in the code doesn't change anything.
Extra observations
I also noticed that with an ear application, composed of one war and one jar, even the procedure described in point 3 in "Preamble" does not work and give the same exception as above. Maybe this information can help.
Someone have some pointers or solutions?
Related questions
Path setting for DLL's in JBOSS 7.1.1
JBoss 7 is trying to load modules libraries from JBoss bin
I finally solve the problem and write here the answer to help other people.
The problem wasn't in the path of the libopencv_java245.so, but in the JBoss Classloaders.
For the case decribed in Preamble point 3 (which worked), the ClassLoader that load the war file is the same that load opencv-245.jar (which is embedded into the war), and the call to System.loadLibrary("opencv_java245") in my code has effect on this same ClassLoader, because it has loaded the Class containing this method call. All has effect on the same ClassLoader and everything work.
Now the reason why it is not working with an ear follow up from the fact that an ear has its own ClassLoader, and then each subdeployment as another one. The first ClassLoader deploy the ear, which contains the opencv-245.jar dependecy, then another ClassLoader deploy the war contained into the ear. Because the call System.loadLibrary("opencv_java245") is in the war, the effect of this command has effect on the ClassLoader of the war, but the opencv-245.jar is loaded into the ear ClassLoader. Thus when trying to call native library, java can't find the link because they are on different ClassLoader.
Finally the point of interest here is for a JBoss module. When describing a module as configured in my initial question, this is a high level JBoss ClassLoader which load the opencv-245.jar. The ClassLoader will also automatically know where to search for native libraries: in $MODULE_PATH/lib/linux-x86_64/. But the problem is to load the library. The call to System.loadLibrary("opencv_java245") must be done in the same ClassLoader that have charged opencv-245.jar. Thus it is not possible to load library like this in your code:
static {
System.loadLibrary("opencv_java245");
}
because it will has effect on the ClassLoader that have load your Class, not on the JBoss one. The solution is to modify the opencv-245.jar and add into it a org.opencv.core.Loader class for instance, which have only one method:
package org.opencv.core
class Loader
{
public static void loadLibrary(String name)
{
System.loadLibrary(name);
}
}
Then in your class you can put:
static {
Loader.loadLibrary("opencv_java245");
}
And the System.loadLibrary call being placed in opencv-245.jar will have effect one the same ClassLoader that load the opencv-245.jar. Then native call are correctly linked because both library, the jar and the so, were loaded in the same ClassLoader.
If you are using OpenCV (org.openpnp package) 3.4.2+ instead of:
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
you can use:
OpenCV.loadLocally();
I'm using jboss wildfly, and had problem when doing more than one deploy. Native classes were already loaded, but this fixed the problem.
Add the libopencv_java245.so file to the same directory you created for your OpenCV module. then add it as a resource so it will be added to the classpath and be available at runtime.
So your module.xml will look like this now:
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="org.opencv">
<resources>
<resource-root path="opencv-245.jar"/>
<resource-root path="."/>
</resources>
<dependencies>
<module name="javax.api"/>
</dependencies>
</module>

Logback include fragment in OSGi container

I have a project a-conf with src/main/resources/logback/conf/a/CommonAppenders.xml file:
<included>
<appender name="FILE" class="FileAppender" />
</included>
Also i have another project a-runable with logback.xml config which imports CommonAppenders.xml:
<configuration>
<!-- this is classpath import -->
<include resource="logback/conf/a/CommonAppenders.xml" />
...
</configuration>
I can compile a-runable in standalone jar with all dependencies (a-conf is one of them) included or as an OSGi bundle. When i run standalone app everything is ok - log files appears as specified in CommonAppenders.xml. But when i run OSGi container no log files are created. I think logback just cannot include resource from classpath because every bundle in OSGi container has its own classloaders (logback uses ClassLoader.getResource() to include file).
I've checked Export-Package: logback.conf.a in a-conf.jar/META-INF/MANIFEST.MF (this is done by maven bundlor plug-in) - it is ok. Added Import-Package: logback.conf.a to a-runable with no effect.
I have no ideas what can i do (no code to change, just configs). Any help would be welcome.
P.S. I've found similar problem here, but logback.xml is already in classpath and its own appenders works fine. Also i do not have any FileNotFoundExceptions in existing logs.
By default, I believe Logback's startup errors are simply dropped if you don't configure a listener (but I may be remembering wrong). The key is likely that a-conf needs to be a Fragment of the bundle that contains logback.jar. That's what I've done for my bundle that has some homebrew appenders.
If you want to see a setup where Logback is pre-configured to output its startup errors to the OSGi container, take a look at Pax-Logger 1.7 - https://github.com/ops4j/org.ops4j.pax.logging/tree/master/pax-logging-logback

Categories