Log4j 2.8 cannot load custom converters in OSGi environment - java

I'm currently switching to log4j2 and I'm working in OSGi environment. There's been couple of issues with OSGi in log4j 2.7 branch which encouraged me to grab 2.8 as the final library.
The thing is I have couple of custom PatternConverters implemented in my project and I can't manage to have them loaded and recognized
DEBUG Initializing configuration XmlConfiguration[location=C:\Program Files\...\etc\log4j2.xml]
.
.
DEBUG Took 0,001043 seconds to load 0 plugins from package common.audit.sink.impl.log4j2.converter
although there's at least 10 of them. This later results in errors like:
DEBUG Building Plugin[name=layout, class=org.apache.logging.log4j.core.layout.PatternLayout].
DEBUG PatternLayout$Builder(pattern="%ED;...
ERROR Unrecognized format specifier [ED]
ERROR Unrecognized conversion specifier [ED] starting at position 3 in conversion pattern.
I have pretty much everything set up as necessary (it worked with 2.7 anyways).
The plugin implementation annotated and both newInstance, format methods implemented according to this guide
The packages declaration in log4j2.xml:
<Configuration status="trace" name="Systemtest_Server" packages="common.audit.sink.impl.log4j2.converter">
The plugins metadata is generated and present in *.jar bundle containing plugins
META-INF\org\apache\logging\log4j\core\config\plugins\Log4j2Plugins.dat
The log4j-core-2.8.jar bundle is activated together with log4j-api-2.8.jar at the startup of Equinox container. The configuration file is pointed by system property and works (obviously from the debug message I receive).
However, I found this issue reported on log4j Jira, which is kind of my problem as I was facing the same exception until I modified log4j-api-2.8.jar to make it import org.apache.logging.log4j.core.util package so my server would start normally. There are some comments suggesting that this might lead to non-extensibility of log4j2 in OSGi.
So is there some way how to overcome this issue (quick fix is enough)? Alternatively, is there something that I might be forgetting to configure here?
Thanks a lot for any help.

Ok, so I'm gonna answer this for myself and maybe it will help somebody too. I did a lot of playing around and the fault was in OSGi with which I'm not so familiar, to be honest.
I found out in the end that you have to ensure these things:
The bundle has to be activated in OSGi container. Inactive bundles are not scanned for plugins. The fact that you mark bundle for activation in your configuration doesn't necessarily mean it will actually happen. E.g., some fault in my bundle's manifest prevent this from happening. So to be sure I build bundle with
Export-Package: common.audit.sink.impl.log4j2.*
Import-Package: *
At least one of following has to hold to get your plugins loaded:
Your bundle with custom plugins is a fragment of log4j-core by stating this in its manifest:
Fragment-Host: org.apache.logging.log4j.core
Probably the right approach.
Your bundle is activated with the same priority as log4j bundles (not only API but also Core needs to be active to enable plugin-search)
Of course the configuration mentioned in my question is needed as well. After this I got no errors and saw a trace like this:
DEBUG Oracle Nashorn Version: 1.8.0_102, Language: ECMAScript, Threading: Not Thread Safe, Compile: true, Names: {nashorn, Nashorn, js, JS, JavaScript, javascript, ECMAScript, ecmascript}
DEBUG Took 0,008133 seconds to load 16 plugins from package common.audit.sink.impl.log4j2.converter
DEBUG PluginManager 'Core' found 112 plugins
DEBUG PluginManager 'Level' found 0 plugins
...
DEBUG Building Plugin[name=layout, class=org.apache.logging.log4j.core.layout.PatternLayout].
DEBUG PatternLayout$Builder(pattern="%ED;%EU;%EL;...
DEBUG Building Plugin[name=appender, class=org.apache.logging.log4j.core.appender.FileAppender].

Related

Logback-classic 1.2.8 DBAppender Missing

I'm trying to upgrade the logback-classic library from version 1.2.3 to 1.2.8. The patch notes say that all DB related code has been removed, so the main DBAppender class no longer exists in the new version https://logback.qos.ch/news.html. Has anyone found some kind of upgrade guide or know of a workaround solution?
Please see https://logback.qos.ch/news.html.
2022-04-20, Release of logback.db version 1.2.11.1
As of logback version 1.2.8 DBAppender no longer ships with logback.
However, DBAppender for logback-classic is available under the
following Maven coordinates:
ch.qos.logback.db:logback-classic-db:1.2.11.1
and for logback-access under
ch.qos.logback.db:logback-access-db:1.2.11.1
Both of these artifacts require
ch.qos.logback.db:logback-core-db:1.2.11.1 which will be pulled in
automatically by Maven's transitivity rules.
I was wondering the same thing after upgrading spring to the 2.6.3 which pulls in logback version 1.2.8+ through spring-boot-starter-logging dependency.
According to logback's site: https://logback.qos.ch/news.html in version 1.2.8: "2) we have removed all database (JDBC) related code in the project with no replacement."
My logback xml configuration file has a custom DB Appender in it and the application failed to build with the following error:
Could not create an Appender of type [ch.qos.logback.classic.db.DBAppender]. ch.qos.logback.core.util.DynamicClassLoadingException: Failed to instantiate type ch.qos.logback.classic.db.DBAppender
After doing some research, I found a ticket in the logback backlog with a request to document how to proceed. https://jira.qos.ch/browse/LOGBACK-1609
Apparently the DB appender was removed due to a vulnerability.
According to the developer: "The source code is still there. Until this issue is resolved, you can fetch the code from tag 1.2.8 and rebuild. The DBAppender issue is a bit more complex than what people think. As you can imagine, we have a lot on my plate these days but we'll get to it eventually."
So it sounds like the code was removed while they work on a fix and support will be added back eventually. I wouldn't count on a quick fix though.
As a workaround I have pinned the logback version in my projects gradle file so that I can use the latest version of spring along with the latest version of logback that still supports the DB appender class.
Here is the syntax I used:
ext['logback.version'] = '1.2.7'

BundleException while trying to start an osgi bundle

I'm trying to install & start a bundle from a osgi jar in the filesystem
Bundle bundle = context.installBundle("reference:file:" + fullPath);
bundle.start();
it worked for another simple bundle, but another more complex bundle has
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
in its manifest
this causes the following exception
(org.osgi.framework.BundleException) org.osgi.framework.BundleException: Unresolved constraint in bundle
Unable to resolve 42.0: missing requirement [42.0] osgi.ee; (&(osgi.ee=JavaSE)(version=1.8))
how do I add this capability to my project?
also how would I remove this require from the other project?
all similiar questions I found didn't answer my question
thanks in advance for any answers and for helping me not pull out my hair :)
Edit:
as christian suggested I tried finding the configuration to felix in netbeans, as the felix framework is loaded by netbeans. I found some configurations inside the maven POM file, but could not use the "org.osgi.framework.system.capabilities" framework property which was mentioned by christian, which I couldn't find in the documentation.
I am putting a bounty as this is really important for me to resolve and is the only thing preventing me from using OSGi as far as I can see
The capability you identified:
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
is a requirement for the osgi.ee namespace. This is the namespace which defines the execution environment for your framework. The filter then says that you need the execution environment to be JavaSE, and that you need the version attribute to be 1.8. This (unsurprisingly) corresponds to Java SE 8.
As others have indicated, this capability should be provided by the OSGi framework. You should not need to do anything to get this to happen. There are two main reasons that this capability would not be present.
You are using an older, or non SE, version of Java. This could easily happen if your NetBeans launch configuration is not using a Java 8 installation.
You are using a Felix framework which does not understand "new" versions of Java. This could be because your Felix framework is old (the latest version is 5.6.4) or because your Java version is very new (are you using a pre-release Java 9 build?).
This really should just work if you can run a newish Felix framework on top of Java 8. Do you have any more details about your environment?
Edit:
You can see the osgi.ee capability provided by the system bundle as follows:
// Get the wiring for the system bundle
BundleWiring wiring = context.getBundle(0).adapt(BundleWiring.class);
// Get the osgi.ee capability for the system bundle
List<Capability> eecaps = wiring.getCapabilities("osgi.ee");
// There must be exactly one capability to show
System.out.println(eecaps.get(0).getAttributes());
This is a capability that needs to be provided by your framework. It means that your project needs to run on Java 8.
It is configured in the framework property:
org.osgi.framework.system.capabilities=osgi.ee; osgi.ee="JavaSE"; version:List<Version>="1.0,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8"
That said normally this is already configured when you for example start the felix distro.
This is a known felix bug which has been fixed in 2.0.4. From http://svn.apache.org/repos/asf/felix/releases/org.apache.felix.bundlerepository-2.0.10/doc/changelog.txt ,
Changes from 2.0.2 to 2.0.4
---------------------------
** Bug
* [FELIX-3097] - LocalRepository is not updated when bundles are
* [FELIX-4571] - NullPointerException when using Repository impl with Aries subsystem impl
* [FELIX-4616] - BundleRepository ResourceComparator violates comparison contract
* [FELIX-4640] - missing (&(osgi.ee=JavaSE)(version=1.8)) when embedding in org.apache.felix.framework
** Improvement
* [FELIX-4812] - BundleRepository can be quite CPU intensive when starting a lot of bundles

WELD OSGI example - no result

I want to do the following solution:Apache Felix + Weld for Java SE (I use felix 4.6.1 and WELD 2.2.10.SP1). For that I want to run one of examples from weld archive - weld-osgi-paint.
I install only the following bundles:
xbean-bundleutils-3.18.jar
pax-cdi-api-0.8.0.jar
pax-cdi-extension-0.8.0.jar
pax-cdi-spi-0.8.0.jar
pax-cdi-extender-0.8.0.jar
pax-swissbox-core-1.8.0.jar
pax-swissbox-lifecycle-1.8.0.jar
pax-swissbox-tracker-1.8.0.jar
ops4j-base-lang-1.5.0.jar
slf4j-api-1.7.6.jar
slf4j-log4j12-1.7.2.jar
log4j-1.2.17.jar
weld-osgi-paint-api.jar
weld-osgi-paint-core.jar
weld-osgi-paint-triangle.jar
weld-osgi-paint-square.jar
I start only two bundles:
org.apache.felix.scr-1.8.2.jar
weld-osgi-paint-core.jar
Besides weld-se.jar and weld-se-core.jar I added to lib path and I export "javax.*" packges from them this way:
String SYSTEM_PACKAGES =
"org.osgi.framework;version=\"1.8\"," +
"org.osgi.util.tracker;version=\"1.8\","+
"org.osgi.service.packageadmin;version=\"1.8\","+
"org.osgi.framework.wiring;version=\"1.8\","+
"javax.swing,javax.management,javax.naming,javax.xml.parsers,"+
"javax.el,javax.enterprise.context;version=\"1.0\","+
"javax.enterprise.event;version=\"1.0\","+
"javax.enterprise.inject;version=\"1.0\","+
"javax.enterprise.util;version=\"1.0\","+
"javax.inject;version=\"1.0\","+
"javax.annotation;version=\"1.1\","+
"javax.enterprise.context.spi;version=\"1.0\","+
"javax.enterprise.inject.spi;version=\"1.0\","+
"org.w3c.dom,org.xml.sax,org.xml.sax.helpers";
configMap.put(Constants.FRAMEWORK_SYSTEMPACKAGES, SYSTEM_PACKAGES);
I start the program and I don't get any errors and exceptions. I get nothing. What do I do wrong?
EDIT 1
I removed slf4j bundles and instead installed pax-logging-api-1.8.2.jar. This is what I get now:
org.ops4j.pax.logging.pax-logging-api[org.ops4j.pax.logging.internal.Activator] : Enabling SLF4J API support.
org.ops4j.pax.logging.pax-logging-api[org.ops4j.pax.logging.internal.Activator] : Enabling Jakarta Commons Logging API support.
org.ops4j.pax.logging.pax-logging-api[org.ops4j.pax.logging.internal.Activator] : Enabling Log4J API support.
org.ops4j.pax.logging.pax-logging-api[org.ops4j.pax.logging.internal.Activator] : Enabling Avalon Logger API support.
org.ops4j.pax.logging.pax-logging-api[org.ops4j.pax.logging.internal.Activator] : Enabling JULI Logger API support.
And thats all. Nothing else. The program doesn't terminate. It just shows nothing else.
I'm not sure what you mean by "adding weld-se* to lib path".
Pax CDI requires weld-osgi-bundle and its dependencies. Weld SE is for Java SE and not for OSGi.
Have a look at Pax CDI integration tests for working examples.
You will need to start the pax-cdi-extender. It processes the example. Btw. I would start all bundles besides the fragments. If they have some active behaviour it makes sense to start them if they are just libs it does not hurt.

CDI stops working when using weld-se-core and weld-servlet-core?

I am playing with Weld-SE. I have a project which has pluggable modules. With one module, weld works. When other module, which uses weld-servlet-core, is put on classpath (with it's deps), CDI stops working, giving errors like "Unable to resolve dependency XY" or (after removing that #Inject) this:
Exception in thread "main" org.jboss.weld.exceptions.DeploymentException: WELD-001417 Enabled interceptor class <class>org.jboss.weld.environment.se.jpa.JpaTransactionInterceptor</class> in jar:file:/mnt/ssd1/data/.m2/repository/org/jboss/jawabot/JawaBot-core/2.0.0-SNAPSHOT/JawaBot-core-2.0.0-SNAPSHOT.jar!/META-INF/beans.xml#11 is neither annotated #Interceptor nor registered through a portable extension
at org.jboss.weld.bootstrap.Validator.validateEnabledInterceptorClasses(Validator.java:466)
...
Although the class has #Interceptor (and the same class works fine with the other module).
When I debug WeldBootstrap#startContainer(Environment environment, Deployment deployment),
deployment.beanDeploymentArchive.beanClasses contains the interceptor
("org.jboss.weld.environment.se.jpa.JpaTransactionInterceptor").
I've checked the dependencies and TattleTale report, they all seem fine.
Any ideas what should I look at / try next?
The project is at http://ondrazizka.googlecode.com/svn/trunk/bots/JawaBot/branches/2.0/ To see the error, run mvn dependency:copy-dependencies java -cp ... org.jboss.jawabot.JawaBotApp Or simply run the web module in NetBeans.
Thanks, Ondra
Update: JIRA: https://issues.jboss.org/browse/WELD-940
Also, I found that it might be caused by a bug in Weld's scanning extension, <weld:scan>.
It was caused by using Weld's scanning extension, <weld:scan>:
An <includes> element contained package wildcard which resulted in matching classes in both "packages" (which is .jar in CDI / Weld's terminology IIUC).
I am not sure if I used it improperly or it's a bug.
See JIRA: https://issues.jboss.org/browse/WELD-940

removing commons-logging and using slf4j causes errors in spring

Specifically, I use spring only for configuring my project through ApplicationContext. In my spring xml I load some bean properties through PropertyPlaceholderConfigurer. Whenever in the dependencies I swap commons-logging-x.x with jcl-slf4j.jar the loading of the context fails with ClassNotFoundExceptions on the placeholder substitutions. Example:
In my spring.xml there is:
<bean id="testbean" class="${testbean.implementingClass}"/>
where testbean.implementingClass is defined in spring.properties:
testbean.implementingClass=my.implementation.TestClass
If I run the project using commons-logging jar all works perfectly. If I change it to jcl-slf4j then I get ClassNotFoundException that the class [${testbean.implementingClass}] was not found, i.e. it does not do the placeholder substituion. Has anyone observed this?
EDIT: My problem doesnt have to do with the jars because:
From http://www.slf4j.org/legacy.html :
Our JCL over SLF4J implementation will allow you to migrate to SLF4J gradually, especially if some of the libraries your software depends on continue to use JCL for the foreseeable future. You can immediately enjoy the benefits of SLF4J's reliability and preserve backward compatibility at the same time. Just replace commons-logging.jar with jcl-over-slf4j.jar. Subsequently, the selection of the underlying logging framework will be done by SLF4J instead of JCL but without the class loader headaches plaguing JCL. The underlying logging framework can be any of the frameworks supported by SLF4J. Often times, replacing commons-logging.jar with jcl-over-slf4j.jar will immediately and permanently solve class loader issues related to commons logging.
When you use jcl-slf4j, you have to make sure you have excluded all commons-logging dependencies from your project. Make sure there is no commons-logging jar anywhere in the classpath.

Categories

Resources