Skip to content

Commit

Permalink
[Fixes #549] Use non-deprecated way of registering Log4j2 plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
grgrzybek committed Sep 30, 2024
1 parent b32c289 commit 3f461c5
Show file tree
Hide file tree
Showing 6 changed files with 348 additions and 4 deletions.
104 changes: 104 additions & 0 deletions pax-logging-log4j2-maven-plugin/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<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/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.ops4j.pax</groupId>
<artifactId>logging</artifactId>
<version>2.2.8-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<groupId>org.ops4j.pax.logging</groupId>
<artifactId>pax-logging-log4j2-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>

<name>OPS4J Pax Logging - Maven plugin</name>

<description>
This plugin is used to generate additional /META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat
files available from additional entries on Bundle-ClassPath.
</description>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-component-metadata</artifactId>
<executions>
<execution>
<goals>
<goal>generate-metadata</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

<dependencies>

<!-- Logging -->

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-layout-template-json</artifactId>
<scope>provided</scope>
</dependency>

<!-- Maven -->

<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
* Copyright 2020 OPS4J.
*
* Licensed 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.ops4j.pax.logging.log4j.maven;

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;

import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.util.PluginRegistry;
import org.apache.logging.log4j.core.config.plugins.util.ResolverUtil;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositorySystem;

/**
* Log4j2 has deprecated {@code org.apache.logging.log4j.core.config.plugins.util.PluginManager#addPackage()} method,
* so we need to allow Log4j to discover another location of {@code Log4j2Plugins.dat} file.
* This plugin generates such file into a Jar which will be added to {@code Bundle-ClassPath} OSGi manifest header
* (because we can't override the file coming from log4j-core...).
*/
@Mojo(name = "generate-log4j-plugin-descriptor", defaultPhase = LifecyclePhase.VERIFY, threadSafe = true, aggregator = true)
public class Generate extends AbstractMojo {

@Parameter(defaultValue = "${project}", readonly = true)
private MavenProject project;

@Parameter(defaultValue = "${session}", readonly = true)
private MavenSession session;

@Inject
private RepositorySystem system;

@Parameter
private String[] plugins;

@Override
public void execute() {
// prepare classpath
Set<String> locations = new LinkedHashSet<>();
locations.add(project.getBuild().getOutputDirectory());
ArtifactHandler artifactHandler = project.getArtifact().getArtifactHandler();
for (Dependency d : project.getDependencies()) {
ArtifactResolutionRequest req = new ArtifactResolutionRequest();
DefaultArtifact artifact = new DefaultArtifact(d.getGroupId(), d.getArtifactId(), d.getVersion(), d.getScope(), d.getType(), d.getClassifier(), artifactHandler);
req.setArtifact(artifact);
ArtifactResolutionResult result = system.resolve(req);
if (!result.hasExceptions()) {
for (Artifact a : result.getArtifacts()) {
locations.add(a.getFile().getAbsolutePath());
}
}
}

List<URL> cp = new ArrayList<>();
for (String loc : locations) {
try {
cp.add(new File(loc).toURI().toURL());
} catch (MalformedURLException ignored) {
}
}

Set<Class<?>> classes = new LinkedHashSet<>();
List<Plugin> foundAnnotations = new LinkedList<>();
Map<Plugin, Class<?>> a2c = new IdentityHashMap<>();
try (URLClassLoader cl = new URLClassLoader(cp.toArray(new URL[0]), Plugin.class.getClassLoader())) {
for (String plugin : plugins) {
try {
Class<?> pluginClass = cl.loadClass(plugin);
getLog().info("Analyzing package " + pluginClass.getPackage().getName());
collectPlugins(cl, pluginClass.getPackage(), foundAnnotations, a2c);
} catch (ClassNotFoundException e) {
getLog().warn("Can't load " + plugin + ":" + e.getMessage());
}
}
} catch (IOException ignored) {
}

// keyed by plugin category
final Map<String, List<Plugin>> pluginMap = new LinkedHashMap<>();
foundAnnotations.forEach(p -> pluginMap.computeIfAbsent(p.category(), k -> new ArrayList<>()).add(p));

// see org.apache.logging.log4j.core.config.plugins.processor.PluginCache.loadCacheFiles()
File log4jPluginDataJar = new File(project.getBuild().getOutputDirectory(), "META-INF/pax-logging-log4j-plugins/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat");
log4jPluginDataJar.getParentFile().mkdirs();
try (final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(Files.newOutputStream(log4jPluginDataJar.toPath())))) {
out.writeInt(pluginMap.size());
for (Map.Entry<String, List<Plugin>> entry : pluginMap.entrySet()) {
String category = entry.getKey();
List<Plugin> pluginsInCategory = entry.getValue();
out.writeUTF(category.toLowerCase(Locale.ROOT));
out.writeInt(pluginsInCategory.size());
for (Plugin plugin : pluginsInCategory) {
// Must always read all parts of the entry, even if not adding, so that the stream progresses
// see org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PluginElementVisitor.visitType()
out.writeUTF(plugin.name().toLowerCase(Locale.ROOT));
out.writeUTF(a2c.get(plugin).getName());
out.writeUTF(Plugin.EMPTY.equals(plugin.elementType()) ? plugin.name() : plugin.elementType());
out.writeBoolean(plugin.printObject());
out.writeBoolean(plugin.deferChildren());

}
}
} catch (IOException e) {
getLog().error("Can't write jar file with Pax Logging Lo4j2 annotation data", e);
}
}

private void collectPlugins(ClassLoader loader, Package pkg, List<Plugin> foundAnnotations, Map<Plugin, Class<?>> a2c) {
final ResolverUtil resolver = new ResolverUtil();
resolver.setClassLoader(loader);
resolver.findInPackage(new PluginRegistry.PluginTest(), pkg.getName());

for (Class<?> cls : resolver.getClasses()) {
final Plugin annotation = cls.getAnnotation(Plugin.class);
if (annotation != null) {
getLog().info(" Found plugin " + cls.getName());
foundAnnotations.add(annotation);
a2c.put(annotation, cls);
}
}
}

}
3 changes: 3 additions & 0 deletions pax-logging-log4j2/osgi.bnd
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

Bundle-Activator: org.ops4j.pax.logging.log4j2.internal.Activator

Bundle-ClassPath: ., META-INF/pax-logging-log4j-plugins

Private-Package: \
org.apache.logging.log4j.core.*; -split-package:=merge-first, \
org.apache.logging.log4j.layout.*; -split-package:=merge-first, \
Expand All @@ -30,6 +32,7 @@ Private-Package: \
Include-Resource: \
{maven-resources}, \
META-INF/maven=target/classes/META-INF/maven, \
META-INF/pax-logging-log4j-plugins=target/classes/META-INF/pax-logging-log4j-plugins, \
META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat=target/classes/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat, \
/=target/classes;filter:=*.json;recursive:=false, \
/=target/classes;filter:=*.xsd;recursive:=false, \
Expand Down
28 changes: 28 additions & 0 deletions pax-logging-log4j2/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,28 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.ops4j.pax.logging</groupId>
<artifactId>pax-logging-log4j2-maven-plugin</artifactId>
<executions>
<execution>
<id>generate-pax-logging-log4j2-plugin-descriptor</id>
<phase>prepare-package</phase>
<goals>
<goal>generate-log4j-plugin-descriptor</goal>
</goals>
<configuration>
<plugins>
<!-- These are equivalents of deprecated org.apache.logging.log4j.core.config.plugins.util.PluginManager.addPackage() call -->
<plugin>org.ops4j.pax.logging.log4j2.internal.bridges.PaxOsgiAppender</plugin>
<plugin>org.apache.logging.log4j.layout.template.json.JsonTemplateLayout</plugin>
<plugin>org.apache.logging.log4j.layout.template.json.resolver.LoggerResolverFactory</plugin>
<plugin>org.apache.logging.log4j.layout.template.json.util.RecyclerFactoryConverter</plugin>
</plugins>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
Expand Down Expand Up @@ -199,6 +221,12 @@
<groupId>org.ops4j.pax.logging</groupId>
<artifactId>pax-logging-api</artifactId>
</dependency>
<dependency>
<!-- for ordering reasons -->
<groupId>org.ops4j.pax.logging</groupId>
<artifactId>pax-logging-log4j2-maven-plugin</artifactId>
<scope>runtime</scope>
</dependency>

<!-- OSGi -->

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,13 @@ public class PaxLoggingServiceImpl implements PaxLoggingService, ServiceFactory<
// We don't have to add "org.apache.logging.log4j.core", because this package will be handled
// using default cache file "/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat"
// taken unchanged from "org.apache.logging.log4j:log4j-core".
PluginManager.addPackage(PaxOsgiAppender.class.getPackage().getName());
PluginManager.addPackage(JsonTemplateLayout.class.getPackage().getName());
PluginManager.addPackage(LoggerResolverFactory.class.getPackage().getName());
PluginManager.addPackage(RecyclerFactoryConverter.class.getPackage().getName());
// plugins are now added using org.ops4j.pax.logging:pax-logging-log4j2-maven-plugin
// and the descriptor it generates, because
// org.apache.logging.log4j.core.config.plugins.util.PluginManager.addPackage() is now deprecated
// PluginManager.addPackage(PaxOsgiAppender.class.getPackage().getName());
// PluginManager.addPackage(JsonTemplateLayout.class.getPackage().getName());
// PluginManager.addPackage(LoggerResolverFactory.class.getPackage().getName());
// PluginManager.addPackage(RecyclerFactoryConverter.class.getPackage().getName());
}

private final BundleContext m_bundleContext;
Expand Down
Loading

0 comments on commit 3f461c5

Please sign in to comment.