Log4J2 not set as logger in OSGi environment - java

I am using commons-logging which should bridge to Log4J2 in an OSGi environment and so have added the dependencies, export-package and import-package in the pom.xml as below but the logger does not get set to Log4J2 logger. No errors are shown but when debugged I found it being set to JDK14Logger.
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>2.8.2</version>
</dependency>
<Export-Package>
org.apache.logging.log4j.*,
org.apache.commons.logging.*
</Export-Package>
<Import-Package>
!org.apache.logging.log4j.*,
!org.apache.commons.logging.*,
*;resolution:=optional
</Import-Package>
[UPDATE]
From the log4j user mailing list I could figure out that due to the non-modular nature of ServiceLoader. I checked out a few usages of ServiceLoader in the OSGi environment to find implementations of interfaces but still couldn't get how this could be gotten to work.
I tried it using pax logging as well but the result is the same except for that the logger is now being set to JclLogger

As Christian said in the other answer, the best fit for logging in OSGI is the pax-logging bundle.
The Pax-logging is built over SLF4J and can be deployed with different possible implementations:
pax-logging-log4j2 (Log4J2)
pax-logging-logback (Logback)
Before we also used pax-logging-service which was using Log4J version 1 but it is not more recommended as the two other implementations works well.
I personally not tested Logback implementation in OSGI, but Log4j2 is working (with some limitations).
One of the good things with this solution is that you must not import any logging implementation on your bundles, the only things have to you do is:
declare slf4j-api as provided dependency (maven scope)
declare eventually the slf4j-simple as test scope in your maven
You don't need to tweak any of the maven-bundle-plugin options regarding logging of any of your bundles.
Here are the step how to do it in ServiceMix version 7.0.1; this release uses originally the pax-logging-services but the next step shows what need to be changed.
By installing the bundles in the startup.properties (immediately after boot time) you ensure that all libs are loaded in the beginning.
These two replace the older version of pax-logging-api and pax-logging-service replaced by pax-logging-log4j2:
mvn\:org.ops4j.pax.logging/pax-logging-api/1.11.13 = 8
mvn\:org.ops4j.pax.logging/pax-logging-log4j2/1.11.13 = 8
then in the file: org.ops4j.pax.logging.cfg you mentions just the line:
org.ops4j.pax.logging.log4j2.config.file=${karaf.etc}/log4j2.xml
and add your log4j2.xml file in the ${karaf.etc} folder (installation of servicemix/etc).
You have to copy the libs in the ${karaf.home}/system folder.
This is if you just need a standard log file.
Now come the limitations: if you need to generate your log as json document, I was only able to use the deprecated JSONLayout in the log4j2.xml.
For setting up JSONLayout you can follow my other answer.
In short:
Add the three Jackson dependencies in startup.properties:
mvn\:com.fasterxml.jackson.core/jackson-annotations/2.12.4 = 6
mvn\:com.fasterxml.jackson.core/jackson-core/2.12.4 = 6
mvn\:com.fasterxml.jackson.core/jackson-databind/2.12.4 = 6
and also the pax-logging-log4j2-extra (if you're using log4j2 implementation):
mvn\:org.ops4j.pax.logging/pax-logging-log4j2-extra/1.11.13 = 6
On my version I had to add the three following lines in overrides.properties:
mvn:com.fasterxml.jackson.core/jackson-core/2.12.4;range="[2,3)"
mvn:com.fasterxml.jackson.core/jackson-databind/2.12.4;range="[2,3)"
mvn:com.fasterxml.jackson.core/jackson-annotations/2.12.4;range="[2,3)"
I created a simple docker-compose with a servicemix 7.0.1 on github with the two ways of creating json logs (the new JsonTemplateLayout not working at the moment).

If the above is in your user bundle then this is not correct.
In your user bundle you should simply use the commons logging API and not change the settings of the maven bundle plugin.
It will then create Import-Package statements for the commons logging API but not for log4j which is what you want.
You then should install a suitable logging framework at runtime. I know that pax-logging can handle commons logging in a OSGi compatible way. Maybe plain log4j2 also works but I am not sure.

Related

Is there an adapter for log4j2 to work over slf4j?

I have a third party library (elasticsearch 5.x) which uses log4j2. My application uses slf4j. Is there an adapter for version 2 of log4j, similar to the version 1 adapter (log4j-over-slf4j)?
Just to clarify: I don't want to actually use log4j or log4j2 as the actual implementation (binding). I use logback for that. So I need a log4j2 to slf4j adapter, not an slf4j binding.
I should also mention that I have found and tried this library (in 2.0-beta version):
https://logging.apache.org/log4j/2.0/log4j-to-slf4j/index.html
but it gives me this error:
Caused by: java.lang.AbstractMethodError: org.apache.logging.slf4j.SLF4JLoggerContextFactory.getContext(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/Object;Z)Lorg/apache/logging/log4j/spi/LoggerContext;
at org.apache.logging.log4j.LogManager.getContext(LogManager.java:175)
at org.apache.logging.log4j.LogManager.getLogger(LogManager.java:426)
at org.elasticsearch.common.logging.ESLoggerFactory.getLogger(ESLoggerFactory.java:49)
at org.elasticsearch.common.logging.Loggers.getLogger(Loggers.java:105)
at org.elasticsearch.common.logging.Loggers.getLogger(Loggers.java:72)
at org.elasticsearch.common.component.AbstractComponent.<init>(AbstractComponent.java:37)
at org.elasticsearch.plugins.PluginsService.<init>(PluginsService.java:98)
at org.elasticsearch.client.transport.TransportClient.newPluginService(TransportClient.java:99)
at org.elasticsearch.client.transport.TransportClient.buildTemplate(TransportClient.java:124)
at org.elasticsearch.client.transport.TransportClient.<init>(TransportClient.java:258)
at org.elasticsearch.transport.client.PreBuiltTransportClient.<init>(PreBuiltTransportClient.java:125)
at org.elasticsearch.transport.client.PreBuiltTransportClient.<init>(PreBuiltTransportClient.java:111)
at org.elasticsearch.transport.client.PreBuiltTransportClient.<init>(PreBuiltTransportClient.java:101)
EDIT: Ok.. so I guess I was just blind yesterday and I was only seeing the beta version of this library. Therefore the answer is that there is such as adapter and it is here:
https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-to-slf4j https://logging.apache.org/log4j/2.0/log4j-to-slf4j/index.html
The latest version currently is 2.8.2
You should include log4j-to-slf4j-2.x.jar
and ensure to NOT include log4j-slf4j-impl-2.x.jar.
See Log4j to SLF4J Adapter for more details.
Log4j2 itself bundles a slf4j implementation (log4j-slf4j-impl-2.x.jar)
This is one of the jars in the Log4j2 distribution.
Update after the question was clarified:
Log4j2 includes a log4j-to-slf4j bridge “. This is what you need to route Log4j2 logging to another slf4j implementation.
The error mentioned is likely a problem of incompatible versions but the question doesn't mention version numbers so it's hard to say.
From https://logging.apache.org/log4j/2.0/faq.html
You can use the log4j-to-slf4j adapter jar when your application calls the Log4j 2 API and you want to route logging calls to a SLF4J implementation.
Slf4j project does not provide bridge from log4j v2 to Slf4j (it hasn't been mentioned in https://www.slf4j.org/legacy.html).
Maven dependencies:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.11.0</version>
</dependency>
Gradle dependency:
compile "org.apache.logging.log4j:log4j-to-slf4j:2.10.0"
Note that above package has transitive dependency on:
org.slf4j:slf4j-api:1.7.25
org.apache.logging.log4j:log4j-api:2.10.0
List of packages: https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-to-slf4j

NoClassDefFoundError: org/slf4j/LoggerFactory with logback

Please help,
For the past couple of days I have been trying to get Logback 1.1.3 to work with my Bukkit plugin. For reference my pom.xml includes these lines:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.3</version>
</dependency>
And the following jars are listed under "Maven Dependencies":
logback-core-1.1.3.jar
logback-classic-1.1.3,jar
slf4j-api-1.7.7.jar (which appeared out of nowhere)
The stacktrace that the server console produces can be found here (line 29 of MoneyDrops.java is:
private static final Logger LOGGER = LoggerFactory.getLogger("MoneyDropsLogger");).
I have also searched through stackoverflow but all the answers suggest that I need to provide an implementation that use the SLF4J api (such as log4j), however, it is to my understanding that logback natively implements the api and that I do not need another jar file.
Any help would be greatly appreciated.
There's a dependency in the pom of logback-classic to slf4j which Maven will resolve. That's the reason of the "appeared out of nowhere".
If I read the documentation of JavaPluginLoader it says:
Represents a Java plugin loader, allowing plugins in the form of .jar
I'm not at all familiar with this library but I would interpret it as "This plugin will only load the specified jar" which would be the MoneyDrops jar.
Line 127 at https://github.com/Bukkit/Bukkit/blob/master/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java actually provides the bukkit classloader and a file as the classpath. I presume the file will be your jar.
So in order to make this work you'd need to somehow make your dependencies available to the classloader of bukkit. Maybe the minecraft server?
Another option is to unpack all the dependencies. The jars are compressed files anyway and repack them with your code. This way you can provide a single jar to the pluginloader. There's a maven plugin doing this for you but I forgot the name.
Thank you all for your help! I have concluded that I do not actually need logging in my plugin anyway (it is not that heavy) and have opted to remove it completely and rely on the Bukkit logger instead. Again, thank you all for your help.

java.lang.NoSuchMethodError: org.apache.log4j.Logger

We use ivy to manage a multi project java application, and recently this error started showing up when we do builds. What's causing this?
This was fixed by adding the following line to the end of the dependencies section in ivy.xml:
<dependencies>
<exclude module="log4j-over-slf4j" />
</dependencies>
Why was it an issue?
Looks like the log4j bridge for sjf4j has an incomplete implementation
This url explains it in more detail.
It looks like the log4j bridge does not implement the full interface for log4j . If you are still using direct log4j calls, you will need both the slf4j bridge jar and the log4j jar
In your case it looks like you excluded the bridge jar, so all slf4j calls go directly to log4j instead of the bridge.
If your code invokes log4j through the xml file , this will work. However if your code programatically invokes log4j initialization this bridge is not going to work
I know this is a very old question but I wanted to share what worked out fine for me. If you have different artifacts of slf4j-log4j* for two projects that are interdependent on each other, for example spring data jpa and spring MVC, this happens. Keep it consistent or even better have a parent pom. In my case I had slf4j-log4j12 on my spring data jpa project and slf4j-log4j13 on my spring MVC one.
Comment this dependency from the pom.xml
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j13</artifactId>
<version>
</dependency>
And add (or keep) the following one:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
Wherever you see a compile time error regarding Log4j, add the following import:
import org.apache.log4j.Logger;

How to use SLF4J when there is multiple SLF4J bindings

When I add the SLF4J logger into my code, I get an error saying, "Class path contains multiple SLF4J bindings." On the website slf4j.org/codes it states that I should remove them from the class path. However, these two loggers are included in my maven dependencies. And my whole maven dependency folder is included into the class path. I'm not in charge of what goes into the maven dependencies, so it's not my place to edit it so that it only has one logger dependency inside the maven dependency folder. Can I specify the Java Program so that it only uses one of the loggers instead?
ejay
Figure out which of your project's dependencies is including an slf4j implementation, then exclude it:
<dependency>
<groupId>other-group</groupId>
<artifactId>dependency-id</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<!-- or slf4j-jdk14, etc -->
<artifactId>slf4j-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
If you're certain you can't adjust the existing maven dependencies to fix the problem, you could make sure your SLF4J binding appears in the classpath first, as the first binding is the one that gets used in the case of multiple bindings.
You'll still get the warning however, but your SLF4J logger will be the one that gets used.
You could also consider utilising maven modules to split the project up into sections so that you can manage the dependencies in each section differently in each module's pom.xml file.

Unable to initialize log4j

I'm trying to initialize log4j-1.2.8 for my application by creating a listener class implemented from the ApplicationLifecycleListener of Weblogic 9.2. When I deploy the application, I'm getting following exceptions:
java.lang.NoClassDefFoundError: org/apache/log4j/spi/RepositorySelector
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
at weblogic.utils.classloaders.GenericClassLoader.defineClass(GenericClassLoader.java:338)
at weblogic.utils.classloaders.GenericClassLoader.findLocalClass(GenericClassLoader.java:291)
at weblogic.utils.classloaders.GenericClassLoader.findClass(GenericClassLoader.java:259)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at weblogic.utils.classloaders.GenericClassLoader.loadClass(GenericClassLoader.java:158)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
at myApp.LoggerStartupService.preStart(LoggerStartupService.java:40)
at weblogic.application.internal.flow.BaseLifecycleFlow$PreStartAction.run(BaseLifecycleFlow.java:187)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:121)
at weblogic.application.internal.flow.BaseLifecycleFlow$BaseAction.invoke(BaseLifecycleFlow.java:95)
at weblogic.application.internal.flow.BaseLifecycleFlow.preStart(BaseLifecycleFlow.java:53)
at weblogic.application.internal.flow.HeadLifecycleFlow.prepare(HeadLifecycleFlow.java:199)
at weblogic.application.internal.BaseDeployment$1.next(BaseDeployment.java:615)
at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:26)
at weblogic.application.internal.BaseDeployment.prepare(BaseDeployment.java:191)
at weblogic.application.internal.DeploymentStateChecker.prepare(DeploymentStateChecker.java:147)
at weblogic.deploy.internal.targetserver.AppContainerInvoker.prepare(AppContainerInvoker.java:61)
at weblogic.deploy.internal.targetserver.operations.ActivateOperation.createAndPrepareContainer(ActivateOperation.java:189)
at weblogic.deploy.internal.targetserver.operations.ActivateOperation.doPrepare(ActivateOperation.java:87)
at weblogic.deploy.internal.targetserver.operations.AbstractOperation.prepare(AbstractOperation.java:217)
at weblogic.deploy.internal.targetserver.DeploymentManager.handleDeploymentPrepare(DeploymentManager.java:718)
at weblogic.deploy.internal.targetserver.DeploymentManager.prepareDeploymentList(DeploymentManager.java:1185)
at weblogic.deploy.internal.targetserver.DeploymentManager.handlePrepare(DeploymentManager.java:247)
at weblogic.deploy.internal.targetserver.DeploymentServiceDispatcher.prepare(DeploymentServiceDispatcher.java:157)
at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer.doPrepareCallback(DeploymentReceiverCallbackDeliverer.java:157)
at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer.access$000(DeploymentReceiverCallbackDeliverer.java:12)
at weblogic.deploy.service.internal.targetserver.DeploymentReceiverCallbackDeliverer$1.run(DeploymentReceiverCallbackDeliverer.java:45)
at weblogic.work.ServerWorkManagerImpl$WorkAdapterImpl.run(ServerWorkManagerImpl.java:518)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:209)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:181)
where myApp.LoggerStartupService is the class implemented from ApplicationLifecycleListener.
I checked the classpath in my scripts and its set properly for all dependencies required for log4j. Appenders & Categories are also there in the log4j.xml. Looks like I'm missing something. Any ideas on what the problem may be?
java.lang.NoClassDefFoundError: org/apache/log4j/spi/RepositorySelector
This means that the in the message mentioned class is missing in the classpath during runtime (while it was available during compiletime of the calling class in question, that's the difference with ClassNotFoundException).
As this is used by Log4j itself, it's thus missing in the Log4j JAR file. The RepositorySelector javadoc learns us that it's introduced in Log4j 1.2. This would mean that there's a collision with another and older-versioned Log4j JAR file in the classpath which got precedence in classloading. It's likely somewhere hidden in one of the default classpaths of Weblogic. I don't do Weblogic, but as hinted by others, you can also try to change the classloading order, if it's supported by Weblogic. Consult its documentation.
where myApp.LoggerStartupService is the class implemented from ApplicationLifecycleListener.
Ok, so you implemented a startup class.
I checked the classpath in my scripts and its set properly for all dependencies required for log4j. Appenders & Categories are also there in the log4j.xml.
How did you setup that classpath? How did you package your startup class and where did you put it? Also, where is log4j.jar, which one do you use? Your startup class (and its dependencies) must be added to the server CLASSPATH. Is this what you did? Refer to Add startup and shutdown classes to the classpath in the official documentation for the details on how to do this.
I'd like to get confirmation of these points (but the final answer is that you should use a MANIFEST.MF in the jar of your startup class to reference third party libraries).
For my case, I using log4j 2.x and cannot find org/apache/log4j/spi/RepositorySelector, because there is no such API in version 2.x, to use it, need add the dependency of log4j-1.2-api
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
<version>2.5</version>
</dependency>
after
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.5</version>
</dependency>

Categories

Resources