Open-liberty how to setup a log4j2 configuration? - java

title says it all. How do I setup a log4j2 configuration in my Open-liberty project? I've added my log4j2.xml file in the resources folder and I use the following dependency in my pom.xml:
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
This is my server.xml:
<server description="Intake Server">
<featureManager>
<feature>servlet-4.0</feature>
<feature>mpConfig-1.4</feature>
<feature>cdi-2.0</feature>
</featureManager>
<variable name="default.http.port" defaultValue="9080"/>
<variable name="default.https.port" defaultValue="9443"/>
<variable name="app.context.root" defaultValue="message"/>
<httpEndpoint httpPort="${default.http.port}"
httpsPort="${default.https.port}" id="defaultHttpEndpoint" host="*" />
<library id="log4jConfig">
<folder dir="/var/log/intake" scanInterval="5s" />
</library>
<webApplication id="intake" location="intake.war" contextRoot="${app.context.root}">
<classloader commonLibraryRef="log4jConfig"/>
</webApplication>
</server>

You'll also need to add log4j to the classpath, and there's several ways you can do that (with pros/cons to each, but I would suggest #2, unless you have more then one app that's going to be making use of log4j, in which case 3 may be the better approach):
Package it with your app (inside the war)
Add it in the server.xml via the classloader attribute under your webApplication
Drop it in the global shared library folder: ${shared.config.dir}/lib/global or ${server.config.dir}/lib/global
Set it via JVM argument: -Dlog4j.configurationFile=file:/path/to/log4j2.xml
I'll mention that there is also an archived repo regarding using log4j with Open Liberty that you may find helpful, but keep in mind that it is archived so it's likely incomplete and with no dev support.

Related

Using lo4j2 in Keycloak custom SPI deployed as JBOSS module

I am struggling to include log4j2 dependency to simple Keycloak SPI.
In general I have log4j2.xml file which is defining RollingFileAppender to log into $JBOSS_HOME/standalone/log/app.log separately from server.log. I have included in gradle build log4j-core, log4j-api and inside the simple implementation of the SPI I have
private static final Logger logger = LogManager.getLogger(TestLoggingEventListenerProvider.class);
Moreover in jboss-deployment-structure I have prevented the server from automatically adding some dependencies as follows and added log4j2 from my dependencies:
<jboss-deployment-structure>
<deployment>
<exclusions>
<!-- Exclusions allow you to prevent the server from automatically adding some dependencies -->
<module name="org.apache.logging.log4j" />
<module name="org.apache.commons.logging"/>
</exclusions>
<dependencies>
<module name="org.apache.logging.log4j2" export="true" />
</dependencies>
</deployment>
Have also setup some properties to instruct jboss where to find log4j2.xml file
/subsystem=logging:write-attribute(name=use-deployment-logging-config,value=false)
/system-property=log4j.configurationFile:add(value=$JBOSS_HOME/standalone/configuration/log4j2.xml)
Would much appreciate if someone can point me to a documentation or a way to do that properly.
Thanks.

Jackson - java.lang.EnumConstantNotPresentException when deserialization with JsonTypeInfo.DEDUCTION

I have SpringBoot app (1.4.3.RELEASE). Recently I have upgraded Jackson (com.fasterxml.jackson.datatype, com.fasterxml.jackson.core) from 2.8.5 to 2.12.2 because of polymorphic subtype deduction feature. Everything works just fine on my local development environment during unit tests and also when I'm running app from IDE.
The problem occurs when I push my changes to build and deploy it on development environment, where app is deployed on Wildfly 21.0.2. (as a WAR archive). Calling ObjectMapper#readValue throws java.lang.EnumConstantNotPresentException (detailed stack below).
There are no enums used in objects which I'm deserializing and I have already checked through Wildfly management console, that there is correct version of Jackson on deployed app. Now I am a bit clueless. Any ideas?
com.fasterxml.jackson.annotation.JsonTypeInfo$Id.DEDUCTION
at com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector._findTypeResolver(JacksonAnnotationIntrospector.java:1424)
at com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector.findTypeResolver(JacksonAnnotationIntrospector.java:522)
at com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair.findTypeResolver(AnnotationIntrospectorPair.java:225)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findTypeDeserializer(BasicDeserializerFactory.java:1584)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findPropertyTypeDeserializer(BasicDeserializerFactory.java:1748)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.resolveMemberAndTypeAnnotations(BasicDeserializerFactory.java:2116)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.constructCreatorProperty(BasicDeserializerFactory.java:1000)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._addExplicitPropertyCreator(BasicDeserializerFactory.java:634)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._addDeserializerConstructors(BasicDeserializerFactory.java:407)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._constructDefaultValueInstantiator(BasicDeserializerFactory.java:283)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findValueInstantiator(BasicDeserializerFactory.java:224)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:220)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:143)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:414)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:349)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:479)
at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4405)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4214)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3214)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3197)
Well, the problem was solved by explicit exclusion of Jackson related libraries in jboss-deployment-structure.xml file (as shown on code below). Without these exlusions Wildfly was forcing its own Jackson lib located in /wildfly/modules/system/layers/base/ path (e.g. wildfly/modules/system/layers/base/com/fasterxml/jackson/core/jackson-core) which is 2.10.5 for Wildfly 21.0.2. Wildfy is doing this regardless of specifing custom version in maven pom.xml. Also I wasn't able to find any mention about this "embedded" Jackson version in Wildfly through management console, so it was a bit pain to realize where is the problem. Maybe this will save someone else some time.
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.3">
<deployment>
<exclusions>
<module name="com.fasterxml.jackson.core.jackson-core" />
<module name="com.fasterxml.jackson.core.jackson-databind" />
<module name="com.fasterxml.jackson.datatype.jackson-datatype-jdk8" />
<module name="com.fasterxml.jackson.datatype.jackson-datatype-jsr310" />
<module name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider" />
<module name="org.jboss.resteasy.resteasy-jackson2-provider" />
</exclusions>
<dependencies>
<module name="jdk.unsupported"/>
</dependencies>
</deployment>
</jboss-deployment-structure>

Jboss EAP 7 - How to exclude implicit modules from deployment (javax.jms)?

I didn't think I would end up here but after a lot of Google and StackOverflow searches here I'm.
This is my exact problem except that I can't afford to make code changes.
The WAR I'm trying to deploy includes a JMS library (i.e. javax.jms, which I cannot exclude form the WAR.) which is already loaded by Jboss EAP 7 by default. The path to jar is something like this jboss/modules/system/layers/base/javax/jms/api/ain/jboss-jms-api_2.0_spec-1.0.0.Final-redhat-1.jar. Because of this two different versions of the same classes loading I'm getting ClassCastException.
org.apache.activemq-ra.ActiveMQConnectionFactory cannot to be cast to javax.jms.ConnectionFactory
So, I want Jboss to NOT load javax.jms so that my application can use the JAR included with the WAR.
So, I was wondering if there was any way to exclude the module globally (for all WAR deployments).
Excluding it per deployment would work too. And I do realize it can be acheivd using jboss-deployment-structure.xml but I can't get it to work.
Here is what I tried:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure
xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
<exclude-subsystems>
<subsystem name="javax" />
<subsystem name="javax.jms" />
</exclude-subsystems>
</deployment>
</jboss-deployment-structure>
and
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure
xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
<exclusions>
<module name="javax" />
<module name="javax.jms" />
<module name="javax.jms.api" />
</exclusions>
</deployment>
</jboss-deployment-structure>
I placed the file in WEB-INF directory. It didn't work. It still loaded the JMS class from modules folder of Jboss EAP. So, how do I correctly do this?
The correct jboss-deployment-structure.xml is here:
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
<exclude-subsystems>
<subsystem name="messaging-activemq"></subsystem>
</exclude-subsystems>
<exclusions>
<module name="javax.jms.api"></module>
</exclusions>
</deployment>
</jboss-deployment-structure>
This way you exclude both messaging subsystem and the JMS api.
You should remove the JMS API JAR from your deployment. You can still keep the JMS implementation JAR in your deployment but that should probably end up in a RAR, preferably outside your deployment.
This link has some things you could try.
Notably:
I think the problem is that activemq-all-5.4.2.jar contains javax.jms.*. Your deployment already gets this implicitly from the javaee.api module (see more information about implicity module dependencies here). I don't think it is appropriate for an application module/jar to package Java EE interfaces. You can try simply deleting the javax directory from activemq-all-5.4.2.jar or using a different set of ActiveMQ jars in your module to limit it to only what you need.
and/or altering your module.xml for ActiveMQ
<module xmlns="urn:jboss:module:1.0" name="activemq">
<resources>
<resource-root path="activemq-all-5.4.2.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
</dependencies>
</module>
There appears to be a method to embed ActiveMQ in Jboss as well, if you're interested. I won't pull out information from that article, as it doesn't answer the original question.

How to prevent Jboss from using log4j for its logging subsystem?

I have a web application which uses Log4j2 and I am deploying it on JbossEAP 6.0.
However I am using some libraries which still use Log4j. So for this I have added the log4j-1.2 api jar provided for log4j2. The issue I am facing is that my application is logging everything using log4j2 but the libraries are still logging using log4j.
I am guessing that this is because Jboss is adding its own copy of log4j to the classpath. Hence I tried by excluding that module by defining it to be excluded in the jboss-deployment-structure.xml file.
However it is still not working.
Please help.Thanks.
jboss-deployment-structure.xml:
<jboss-deployment-structure>
<deployment>
<!-- Exclusions allow you to prevent the server from automatically adding some dependencies -->
<exclusions>
<module name="org.apache.log4j" />
</exclusions>
</deployment>
</jboss-deployment-structure>

JRebel do not detect web resource changes over multiple webapp folders

I have a modular web project and thus I am allowing modules to be a war archive including webapp folder. Using the following rebel.xml works fine on detecting class changes over all modules. But for some reason jrebel does not move when a html or js is changed.
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com"
xsi:schemaLocation="http://www.zeroturnaround.com http://www.zeroturnaround.com/alderaan/rebel-2_0.xsd">
<classpath>
<!-- appserver -->
<dir name="/home/xx/data/appserver/target/classes/main"/>
<dir name="/home/xx/data/appserver/target/resources/main"/>
<!-- module -->
<dir name="/home/xx/data/as.module.core/target/classes/main"/>
<dir name="/home/xx/data/as.module.core/target/resources/main"/>
<dir name="/home/xx/data/as.module.mqlcore/target/classes/main"/>
<dir name="/home/xx/data/as.module.mqlcore/target/resources/main"/>
</classpath>
<!-- web>
<link target="/">
<dir name="/home/xx/data/appserver/src/main/webapp"/>
<dir name="/home/xx/data/as.module.core/src/main/webapp"/>
<dir name="/home/xx/data/as.module.mqlcore/src/main/webapp"/>
</link>
</web -->
<web>
<link target="/">
<dirset dir="/home/xx/data">
<include name="**/src/main/webapp"/>
</dirset>
</link>
</web>
</application>
EDIT:
Interesting fact is. When I use the commented part of web configuration all three webapp folders are in the log and will be monitored for changes. But the application server can not find all of the webapp files. When I use the second <web> configuration all files are seen by the application server but are not observed by jrebel. I think it is not possible to have multiple directories linked to "/"
Each of the modules eg .war or .jar files need to have their own rebel.xml files. Otherwise all of them will reload same resources and when having different classloaders all kind of weird things can happen.
It is possible to check which instance of the file JRebel actually uses by searching "found resource" from jrebel.log. It should be written something like this
sun.misc.Launcher$AppClassLoader#184be29 found resource: 'cfg/log4j.xml' from 'file:/C:/Projects/testproject/Trunk/edm/target/cfg/log4j.xml'.
It is also seen which of the file changed by loking up lines with Event like this:
[IntelliJFSNotify] Event 'CHANGE' on: 'C:/Projects/testproject/Trunk/edm/target/cfg/log4j.xml'
Usually found resource and changed file paths do not match if the file is not reloaded. If they do match then it is recommended to send absolute path of the file and jrebel.log to support#zeroturnaround.com for investigation.
Ok, the answer is: indeed it is not possible to configure more than one directory under the <web><link target="/"></link></web> configuration. I have now a folder ./target/all-webapp where I smylink (cp -sR) all files via gradle task ... not nice but works ... and thank god jrebel is following symlinks!

Categories