You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by pk...@apache.org on 2023/01/20 09:18:20 UTC

[logging-log4j2] 01/02: [LOG4J2-3546] Fix SLF4J and JUL implementation in OSGi environment

This is an automated email from the ASF dual-hosted git repository.

pkarwasz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit cb0be38f8977ad144d0624ce5acbf0f3124781d6
Author: Piotr P. Karwasz <pi...@karwasz.org>
AuthorDate: Sun Jul 3 21:04:11 2022 +0200

    [LOG4J2-3546] Fix SLF4J and JUL implementation in OSGi environment
    
    Tests `log4j-to-jul` and `log4j-to-slf4j` in an OSGI environment.
    
    Newer tests in `log4j-osgi` are written using PAX Exam in order to
    provide better OSGI testing.
---
 log4j-bom/pom.xml                                  |  6 ++
 log4j-osgi/pom.xml                                 | 53 ++++++++++++++--
 .../log4j/osgi/tests/AbstractLoadBundleTest.java   | 24 ++++---
 .../logging/log4j/osgi/tests/AbstractOsgiTest.java | 18 ------
 .../logging/log4j/osgi/tests/JULProviderTest.java  | 70 ++++++++++++++++++++
 .../log4j/osgi/tests/SLF4JProviderTest.java        | 69 ++++++++++++++++++++
 .../log4j/osgi/tests/junit/BundleTestInfo.java     | 74 ----------------------
 log4j-to-jul/pom.xml                               |  2 +-
 8 files changed, 203 insertions(+), 113 deletions(-)

diff --git a/log4j-bom/pom.xml b/log4j-bom/pom.xml
index d5b305ac0c..5f21d56331 100644
--- a/log4j-bom/pom.xml
+++ b/log4j-bom/pom.xml
@@ -298,6 +298,12 @@
         <artifactId>log4j-taglib</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <!-- Log4j-to-JUL bridge -->
+      <dependency>
+        <groupId>org.apache.logging.log4j</groupId>
+        <artifactId>log4j-to-jul</artifactId>
+        <version>${project.version}</version>
+      </dependency>
       <!-- SLF4J Adapter -->
       <dependency>
         <groupId>org.apache.logging.log4j</groupId>
diff --git a/log4j-osgi/pom.xml b/log4j-osgi/pom.xml
index 3fa7fb2584..b6b076dbd8 100644
--- a/log4j-osgi/pom.xml
+++ b/log4j-osgi/pom.xml
@@ -32,6 +32,7 @@
     <projectDir>/osgi</projectDir>
     <module.name>org.apache.logging.log4j.osgi</module.name>
     <maven.doap.skip>true</maven.doap.skip>
+    <pax.exam.version>4.13.5</pax.exam.version>
   </properties>
   <dependencies>
     <dependency>
@@ -55,8 +56,19 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.apache.commons</groupId>
-      <artifactId>commons-lang3</artifactId>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-to-jul</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-to-slf4j</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j.samples</groupId>
+      <artifactId>log4j-samples-configuration</artifactId>
+      <version>${project.version}</version>
       <scope>test</scope>
     </dependency>
     <dependency>
@@ -75,11 +87,19 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.apache.logging.log4j.samples</groupId>
-      <artifactId>log4j-samples-configuration</artifactId>
-      <version>${project.version}</version>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-core</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.framework</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.apache.maven</groupId>
       <artifactId>maven-core</artifactId>
@@ -124,6 +144,19 @@
   </dependencies>
   <build>
     <plugins>
+      <plugin>
+        <groupId>org.ops4j.pax.exam</groupId>
+        <artifactId>exam-maven-plugin</artifactId>
+        <version>${pax.exam.version}</version>
+        <executions>
+            <execution>
+                <phase>generate-test-resources</phase>
+                <goals>
+                    <goal>generate-link-files</goal>
+                </goals>
+            </execution>
+        </executions>
+      </plugin>
       <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
@@ -150,8 +183,14 @@
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <!-- Skipping tests as I don't know why they are failing -->
-          <skip>false</skip>
+          <classpathDependencyExcludes>
+            <classpathDependencyExclude>org.osgi:org.osgi.framework</classpathDependencyExclude>
+          </classpathDependencyExcludes>
+          <systemPropertyVariables>
+            <!-- PAX logging has a copy of Log4j2 API-->
+            <pax.exam.logging>false</pax.exam.logging>
+            <java.protocol.handler.pkgs>org.ops4j.pax.url</java.protocol.handler.pkgs>
+          </systemPropertyVariables>
         </configuration>
       </plugin>
     </plugins>
diff --git a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java
index 0c9f1c92a1..a73202ca22 100644
--- a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java
+++ b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java
@@ -20,7 +20,6 @@ import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
-import java.nio.file.Path;
 
 import org.junit.Assert;
 import org.junit.Test;
@@ -32,33 +31,32 @@ import org.osgi.framework.BundleException;
  */
 public abstract class AbstractLoadBundleTest extends AbstractOsgiTest {
 
+    private Bundle installBundle(String symbolicName) throws BundleException {
+        // The links are generated by 'exam-maven-plugin'
+        final String url = String.format("link:classpath:%s.link", symbolicName);
+        return getBundleContext().installBundle(url);
+    }
+
     private Bundle getApiBundle() throws BundleException {
-        final Path apiPath = getHere().resolveSibling("log4j-api").resolve("target").resolve(getBundleTestInfo().buildJarFileName("log4j-api"));
-        return getBundleContext().installBundle(apiPath.toUri().toString());
+        return installBundle("org.apache.logging.log4j.api");
     }
 
     private Bundle getPluginsBundle() throws BundleException {
-        final Path apiPath = getHere().resolveSibling("log4j-plugins").resolve("target").resolve(getBundleTestInfo().buildJarFileName("log4j-plugins"));
-        return getBundleContext().installBundle(apiPath.toUri().toString());
+        return installBundle("org.apache.logging.log4j.plugins");
     }
 
-
     private Bundle getCoreBundle() throws BundleException {
-        final Path corePath = getHere().resolveSibling("log4j-core").resolve("target").resolve(getBundleTestInfo().buildJarFileName("log4j-core"));
-        return getBundleContext().installBundle(corePath.toUri().toString());
+        return installBundle("org.apache.logging.log4j.core");
     }
 
     private Bundle getDummyBundle() throws BundleException {
-        final Path dumyPath = getHere().resolveSibling("log4j-samples").resolve("log4j-samples-configuration").resolve("target").resolve(getBundleTestInfo().buildJarFileName("log4j-samples-configuration"));
-        return getBundleContext().installBundle(dumyPath.toUri().toString());
+        return installBundle("org.apache.logging.log4j.samples.log4j-samples-configuration");
     }
 
     private Bundle get12ApiBundle() throws BundleException {
-        final Path apiPath = getHere().resolveSibling("log4j-1.2-api").resolve("target").resolve(getBundleTestInfo().buildJarFileName("log4j-1.2-api"));
-        return getBundleContext().installBundle(apiPath.toUri().toString());
+        return installBundle("org.apache.logging.log4j.1.2-api");
     }
 
-
     private void log(final Bundle dummy) throws ReflectiveOperationException {
         // use reflection to log in the context of the dummy bundle
 
diff --git a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java
index a717c464f5..a8db58438f 100644
--- a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java
+++ b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java
@@ -16,10 +16,6 @@
  */
 package org.apache.logging.log4j.osgi.tests;
 
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-import org.apache.logging.log4j.osgi.tests.junit.BundleTestInfo;
 import org.apache.logging.log4j.osgi.tests.junit.OsgiTestRule;
 import org.junit.Before;
 import org.junit.Rule;
@@ -33,10 +29,6 @@ public abstract class AbstractOsgiTest {
 
     private BundleContext bundleContext;
 
-    private final BundleTestInfo bundleTestInfo;
-
-    private Path here;
-
     @Rule
     public OsgiTestRule osgi = new OsgiTestRule(getFactory());
 
@@ -45,7 +37,6 @@ public abstract class AbstractOsgiTest {
      */
     public AbstractOsgiTest() {
         super();
-        this.bundleTestInfo = new BundleTestInfo();
     }
 
     /**
@@ -54,21 +45,12 @@ public abstract class AbstractOsgiTest {
     @Before
     public void before() {
         bundleContext = osgi.getFramework().getBundleContext();
-        here = Paths.get(".").toAbsolutePath().normalize();
     }
 
     public BundleContext getBundleContext() {
         return bundleContext;
     }
 
-    public BundleTestInfo getBundleTestInfo() {
-        return bundleTestInfo;
-    }
-
     protected abstract FrameworkFactory getFactory();
 
-    public Path getHere() {
-        return here;
-    }
-
 }
diff --git a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/JULProviderTest.java b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/JULProviderTest.java
new file mode 100644
index 0000000000..49e0587072
--- /dev/null
+++ b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/JULProviderTest.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.osgi.tests;
+
+import java.util.Optional;
+import java.util.stream.Stream;
+import javax.inject.Inject;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
+import org.apache.logging.log4j.tojul.JULLoggerContextFactory;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.linkBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class JULProviderTest {
+
+    @Inject
+    private BundleContext context;
+
+    @Configuration
+    public Option[] config() {
+        return options(
+                linkBundle("org.apache.logging.log4j.api"),
+                linkBundle("org.apache.logging.log4j.to-jul"),
+                // required by Pax Exam's logging
+                linkBundle("slf4j.api"),
+                linkBundle("ch.qos.logback.classic"),
+                linkBundle("ch.qos.logback.core"),
+                junitBundles());
+    }
+
+    @Test
+    public void testJulFactoryResolves() {
+        final Optional<Bundle> julBundle = Stream.of(context.getBundles())
+                .filter(b -> "org.apache.logging.log4j.to-jul".equals(b.getSymbolicName()))
+                .findAny();
+        assertTrue(julBundle.isPresent());
+        final LoggerContextFactory factory = LogManager.getFactory();
+        assertEquals(JULLoggerContextFactory.class, factory.getClass());
+    }
+}
diff --git a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/SLF4JProviderTest.java b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/SLF4JProviderTest.java
new file mode 100644
index 0000000000..7f46786978
--- /dev/null
+++ b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/SLF4JProviderTest.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.osgi.tests;
+
+import java.util.Optional;
+import java.util.stream.Stream;
+import javax.inject.Inject;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
+import org.apache.logging.slf4j.SLF4JLoggerContextFactory;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.linkBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class SLF4JProviderTest {
+
+    @Inject
+    private BundleContext context;
+
+    @Configuration
+    public Option[] config() {
+        return options(
+                linkBundle("org.apache.logging.log4j.api"),
+                linkBundle("org.apache.logging.log4j.to-slf4j"),
+                linkBundle("slf4j.api"),
+                linkBundle("ch.qos.logback.classic"),
+                linkBundle("ch.qos.logback.core"),
+                junitBundles());
+    }
+
+    @Test
+    public void testSlf4jFactoryResolves() {
+        final Optional<Bundle> slf4jBundle = Stream.of(context.getBundles())
+                .filter(b -> "org.apache.logging.log4j.to-slf4j".equals(b.getSymbolicName()))
+                .findAny();
+        assertTrue(slf4jBundle.isPresent());
+        final LoggerContextFactory factory = LogManager.getFactory();
+        assertEquals(SLF4JLoggerContextFactory.class, factory.getClass());
+    }
+}
diff --git a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/junit/BundleTestInfo.java b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/junit/BundleTestInfo.java
deleted file mode 100644
index 02596168d8..0000000000
--- a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/junit/BundleTestInfo.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-
-package org.apache.logging.log4j.osgi.tests.junit;
-
-import java.io.FileReader;
-import java.io.IOException;
-
-import org.apache.maven.model.Model;
-import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
-import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-/**
- * Provides tests with bundle information. Reads the {@code pom.xml} in the current directory to get project settings.
- */
-public class BundleTestInfo {
-
-    private final MavenProject project;
-
-    /**
-     * Constructs a new helper objects and initializes itself.
-     */
-    public BundleTestInfo() {
-        try (final FileReader reader = new FileReader("pom.xml")) {
-            // get a raw POM view, not a fully realized POM object.
-            final Model model = new MavenXpp3Reader().read(reader);
-            this.project = new MavenProject(model);
-        } catch (final IOException | XmlPullParserException e) {
-            throw new IllegalStateException("Could not read pom.xml", e);
-        }
-    }
-
-    public String buildJarFileName(final String artifactId) {
-        return artifactId + "-" + getVersion() + ".jar";
-    }
-
-    /**
-     * Gets the Maven artifact ID.
-     *
-     * @return the Maven artifact ID.
-     */
-    public String getArtifactId() {
-        return project.getArtifactId();
-    }
-
-    /**
-     * Gets the Maven version String.
-     *
-     * @return the Maven version String.
-     */
-    public String getVersion() {
-        return project.getVersion();
-    }
-
-    @Override
-    public String toString() {
-        return "BundleTestInfo [project=" + project + "]";
-    }
-}
diff --git a/log4j-to-jul/pom.xml b/log4j-to-jul/pom.xml
index b3637c19fb..9b4dc81168 100644
--- a/log4j-to-jul/pom.xml
+++ b/log4j-to-jul/pom.xml
@@ -67,7 +67,7 @@
         <artifactId>maven-bundle-plugin</artifactId>
         <configuration>
           <instructions>
-            <Export-Package>org.apache.logging.tojul</Export-Package>
+            <Export-Package>org.apache.logging.log4j.tojul</Export-Package>
           </instructions>
         </configuration>
       </plugin>