10

I'm trying to use log4j2 OSGi bundles, but it seems log4j2 api cannot find log4j2 core in an OSGi environment. I'm continuously getting the following exception :

ERROR StatusLogger Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console

I found the same exception discussed in few places but still I could not figure out this issue. Isuspect I'm getting this issue because log4j2 api cannot find the log4j-provider.properties inside the META-INF directory of log4j2 core. Is there any clue why I'm getting this exception and how can I correct the issue ? (If anybody has correct pom file for adding log4j dependencies and bundling please share it with me)

These are the dependencies I have used

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.2</version>
    </dependency>

I use apache felix as the bundle plugin. This error occures because resources inside the META-INF of log4j2-core specially the log4j-providoer.properties file is not visible to log4j api.

Thanks!

Grant
  • 4,413
  • 18
  • 56
  • 82
  • Do you load the log4j-core bundle? How do you manage your dependencies? With Maven? – Puce May 07 '15 at 08:28
  • I added both log4j2 core and api in dependencies. – Grant May 13 '15 at 09:51
  • Can you specify which framework are you using? That properties file is not accessible from another bundle context, a mechanism to load it from -core is needed, see my tentative answer. – uraimo May 14 '15 at 21:05
  • I'm using Felix and the OSGi environment is based on the Eclipse Equinox. – Grant May 15 '15 at 02:48
  • Actually log4j2 OSGi bundles works without any issue if we use them in a pure Eclipse equinox environment. I'm getting this exception because the application I'm using has a customized version of Equinox. So note that there is no any issue with the log4j2 OSGi latest bundles they are working properly in an OSGi environment. – Grant May 21 '15 at 11:08
  • Same issue in IntelliJ and also for javax.servlet.Servlet – Zach Apr 17 '23 at 17:29

5 Answers5

9

The log4j-core bundle registers a bundle listener when the Activator is started and starts searching for log plugins and if something is found it performs a sequence of operations similar to the usual Logger initialization (not really idiomatic OSGi stuff and i'm not sure it works, but it seems to set at least Log4jContextSelector and LoggerContextFactory), just to be sure of it, did you install and start the log4j-core bundle and verified that nothing changed?

Update:

I did some testing and found what is an acceptable solution/workaround for log4j2 OSGi issues. But as someone else recommended, alternatively i would use slf4j, pax-logging or simply the OSGi Log Service (the simpler of the bunch).

@Grant, you have 2 separate things that need to be fixed:

1. As you described, the "Log4j2 could not find a logging implementation" error is caused by the fact that the log4j2-api bundle is unable to find the log4j-provider.properties file and, after that is fixed, log4j2-api cannot find the log4j2-core classes (it's a different bundle and log4j2-api doesn't have a specific Import-Package: for those classes).

The workaround for this is to create a small fragment bundle for log4j2-api (i called mine log4j-api-config.jar) with that .properties file in META-INF and a manifest that forces a dynamic import:

    Manifest-Version: 1.0
    Bundle-ManifestVersion: 2
    Bundle-Name: Log4j API configurator
    Bundle-SymbolicName: org.apache.logging.log4j.apiconf
    Bundle-Version: 1.0.0
    Bundle-Vendor: None
    Bundle-RequiredExecutionEnvironment: OSGi/Minimum-1.2
    Fragment-Host: org.apache.logging.log4j.api
    DynamicImport-Package: *

I'm importing * here, you can improve it adding the required subset of log4j2-core packages that log4j2-api needs.

With this, that error will disappear, but log4j will notice that you didn't provide a log4j2 configuration file, next thing to fix (only if you care in this case).

2. At this point Felix will display this:

log4j2.xml not found by org.apache.logging.log4j.core
ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.

and i suppose you could want to add your own log4j2.xml without messing with the original log4j2-core.jar. You can do this creating another fragment bundle, this time hosted by log4j2-core, with just a log4j2.xml configuration file in the root and a simple manifest:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Log4j Core configurator
Bundle-SymbolicName: org.apache.logging.log4j.coreconf
Bundle-Version: 1.0.0
Bundle-Vendor: None
Bundle-RequiredExecutionEnvironment: OSGi/Minimum-1.2
Fragment-Host: org.apache.logging.log4j.core

I used this simple log4j2.xml configuration during my tests:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="info">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

With this you will not need that sort of "bridge" bundle you described below anymore, and you'll just need a simple Import-Package: org.apache.logging.log4j to use log4j from your bundle.

Update 2:

Important to note that the two fragments are NOT dependencies of the original bundles (no need to modify log4j jars or or even your bundles to add import/export), so the original bundles and your own custom ones will remain untouched. Also, they don't depend on the original bundle either, they are just basic jar archive with a manifest and an additional text file, no code, no need for Import-Package or Export-Package.

You just need to install each fragment after their host bundle is installed.

I've created both fragments manually starting from an empty jar and copying inside the archive the properties file and modifying the MANIFEST.MF with a text editor, you can create them both with this pom.xml, remember to copy log4j-provider.properties where pom.xml is located.

For the log4j2-api fragment:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>my.group</groupId>
    <artifactId>log4j2-api-config</artifactId>
    <version>1.0</version>
    <name>log4j2-api-config</name>
    <packaging>bundle</packaging>
    <properties>
        <java-version>1.7</java-version>
    </properties>

    <dependencies>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <version>2.0.0</version>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>org.apache.logging.log4j.apiconf</Bundle-SymbolicName>
                        <Bundle-Name>Log4j API Configurator</Bundle-Name>
                        <Bundle-Version>1.0.0</Bundle-Version>
                        <Fragment-Host>org.apache.logging.log4j.api</Fragment-Host>
                        <DynamicImport-Package>
                            *;resolution:=optional
                        </DynamicImport-Package>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>.</directory>
                <includes>
                    <include>log4j-provider.properties</include>
                </includes>
                <targetPath>META-INF</targetPath>
            </resource>
        </resources>
    </build>
</project>

Modify this pom where appropriate(included file, bundle names) to generate the other one with the log4j2-core configuration.

uraimo
  • 19,081
  • 8
  • 48
  • 55
  • I'm using Felix, In OSGi console I can see all log4j-api and log4j-core in active state, however I'm getting the above mentioned error. This is working fine if I crate a separate bundle with the dependencies for api and core and export org.apache.logging.* package and also need to copy log4j-provider.properties file in to the META-INF directory of that bundle, but I want to use directly log4j2 OSGi bundles. – Grant May 15 '15 at 03:04
  • Can you please share the pom.xml s you have used ? Do we need to add this fragment as a dependency where we use log4j2? – Grant May 15 '15 at 10:58
  • 1
    Added a pom to generate the -api-config jar using felix's maven-bundle-plugin. No need to add them as dependencies anywhere, just install these two fragments, and they will *merge* their content with the original bundles. – uraimo May 15 '15 at 11:56
  • Thanks for the answer this works fine in pure equinox environment, but if I have custom Converter plugin inside a bundle, log4j2 cannot find that plugin, so that I'm getting "Unrecognized format specifier" exception. Any idea about this ? – Grant May 16 '15 at 17:41
  • Searching for that error, among other things i've found hints to the fact that `META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat` could not be loaded, you could try including it in the core fragment, but considering you have built a custom converter i'm not too sure it will fix it. – uraimo May 16 '15 at 20:12
1

Log4j is not suitable for an OSGi environment. Luckily there is a nice drop in replacement pax-logging. In your bundle you use the log4j api or any other of the supported apis (I prefer slf4j-api). Then you deploy pax logging to your OSGi framework and your bundle. You can configure pax logging using a standard log4j config. So it is very easy to use. If you want a really easy start you can simply install apache karaf and deploy your bundle to it. Karaf already includes a fully set up pax logging.

Christian Schneider
  • 19,420
  • 2
  • 39
  • 64
  • This is not a good option since I asked the question for log4j2 – Grant May 13 '15 at 09:50
  • Log4j is not built for OSGi. Pax logging is the only option I know. It is not a bad option though as on the development side you use the log4j API as before. – Christian Schneider May 13 '15 at 10:13
  • 1
    How can we say log4j2 is not built for OSGi ? – Grant May 13 '15 at 11:31
  • 1
    This is what the developers told me when I asked for improvements in OSGi support. One problem with log4j in OSGi is that it can only load configs from inside the bundle using log4j. This means that each bundle needs its own config and that it is not possible to change the config at runtime. Pax logging uses the OSGi standard mechanism configuration admin to externalize the config. So you can have one config for all bundles and change it at runtime. Another issue are appenders. Log4j appenders have to be inside the bundle using the logging. In pax logging you can install them at runtime. – Christian Schneider May 13 '15 at 13:09
  • Thanks for the explanation, but I want to use log4j2 – Grant May 13 '15 at 13:15
  • 1
    I just checked at log4j jira. Apparently they are working on OSGi support for log4j2. As you can see parts are done but many steps are still unresolved. See https://issues.apache.org/jira/browse/LOG4J2-515 So maybe it will work soon .. On the the hand some of the issues are from 2008. – Christian Schneider May 13 '15 at 13:17
0

Try changing the name of the jar file something does not contain core word (eg:log4j-zore) and try again

mfidan
  • 647
  • 5
  • 19
0

You need specify OSGI related dependencies on Your bundle in META-INF/MANIFEST.MF by add the following dependencies:

Require-Bundle: org.apache.logging.log4j.core;org.apache.logging.log4j.api

0

For me this error is resolved by:

  • ensuring that the log4j-api bundle is actually activated - and not just resolved - before calling the logger. I did this by setting it to Auto-Start with a low start level.
  • let log4j-api import classes of log4j-core (as mentioned by @uraime) to make sure it finds log4j-core. The cleanest way to do this is using a fragment. Instead of dynamic import you could also add this to the manifest:

    Require-Bundle: org.apache.logging.log4j.core

I also use a fragment for log4j-core to let it find my log4j2.xml configuration file, but when not using this fragment, log4j will show a different error message.

Additionally I found that it's not required for the log4j-core bundle to be activated (only resolved) but note that this does mean that the Activator cannot find custom log4j2 plugins.

Henno Vermeulen
  • 1,495
  • 2
  • 15
  • 25
  • Within my Eclipse workspace I somehow did not need the fragment with Dynamic import for log4j-api. It was able to load log4j-core without doing this. But in my final product build I still got the same error. My bundles configuration is exactly the same - up to ordering! I suspect that the log4j-api (2.3.0) is doing some classloading tricks (perhaps with thread context classloader) that may or may not work in OSGi depending on the OSGi implementation (for me: org.eclipse.osgi_3.7.2.v20120110-1415.jar) order in which the bundles are resolved.) – Henno Vermeulen Sep 17 '15 at 08:36