Log4j2 custom plugins not working in EAR

2019-09-02 10:58发布

问题:

I am migrating an EAR application from Log4J 1.2.17 to Log4J2 2.4. Please find below the EAR structure.

EAR
-- APPLICATION JAR 1 (contains custom plugin)
-- APPLICATION JAR 2
-- APPLICATION JAR 3 (contains custom plugin)
-- APPLICATION JAR 4
-- APPLICATION WAR 1
-- APPLICATION WAR 2
-- APPLICATION WAR 3
-- OTHER THIRD PARTY APIs
-- lib/log4j-api-2.4.jar
-- lib/log4j-core-2.4.jar
-- lib/log4j-jcl-2.4.jar
-- lib/log4j-web-2.4.1.jar
-- META-INF/log4j2.xml
-- META-INF/MANIFEST.MF (contains all jars in class-path entry)

Custom plugin classes in all the jars are in the same package - com.test.it.logging.

PFB the initialization code.

  1. Adding the custom plugins package.

    PluginManager.addPackage("com.test,it.logging");

  2. Initializing the logging configuration using log4j2.xml.

String path = "path/log4j2.xml";
System.setProperty("log4j.configurationFile", path);

None of the defined custom plugins are getting detected and I tried all the combinations available to initialize log4j2.xml and plugins initialization but nothing worked.

It gives me a feel that custom plugins is not at all working in EAR as I tried all the permutations and combinations. is this a BUG in log4j2 (version: 2.4) ? If no, then please guide me about how to define logging configuration containing custom plugins in an EAR containing custom plugins that are scattered across many jars within an EAR ?

Can anyone please let me know about how to configure

Also, PFB my question posted in stackoverflow on the same.

Custom plugin not getting detected in EAR with log4j2 API

I am using Wildfly 8.2.0-Final AS and maven for building EAR.

Just adding a note that I am always finding Log4JPlugins.dat file inside Jars containing custom plugins irrespective of the options I try regarding detecting plugins.

Your response is highly important to me and thanks.

回答1:

I don't believe the log4j classes have visibility into the classloaers for the war and application jars.



回答2:

When compiling a custom Plugin, the Log4J pom.xml defines a plugin that automatically generates cache data in the file META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat You can see this under your target/classes in a Maven project.

The log4j-core-2.x.x.jar also contains a Log4j2Plugins.dat defining its cache data.

The problem is a single JAR is created when testing an EAR using ShrinkWrap and normally the log4j-core-2.x.x.jar Log4j2Plugins.dat is added to the test JAR as it would most likely be first in the class path.

This means your custom plugin cache is missing.

The solution using ShrinkWrap is to create a new Log4j2Plugins.dat merging any required custom plugin cache files with the cores and then adding that to the JAR.

The following function achieves that...

private static void mergeLog4J2Log4j2PluginsFile(JavaArchive ja, Class... uniqueJARClasses) {
  // @Author: Johnathan Ingram <jingram@rogueware.org>
  // Log4J2 uses /META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat within a JAR to define custom plugins
  //        This is automatically generated by the plugin defined in the log4j-core-2.x.x pom.xml when compiling your custom plugin
  //        The problem with shrinkwrap is that the JAR is not preserved and only a single 
  //        /META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat
  //        file can exist as JAR files cannot be added to a JAR file as a library.
  //        This is normally the default contained in log4j-core-2.x.x.jar which does not expose any custom plugins
  //        To rectify, both the core and the custom plugin JAR file Log4j2Plugins.dat need to be merged into a single Log4j2Plugins.dat
  try {
     // List of a unique class in each JAR containing a Log4j2Plugins.dat requiring merging
     Vector<URL> datUrls = new Vector<URL>();
     for (Class klass : uniqueJARClasses) {
        // Find  the JAR the class belongs to
        URL classLoc = klass.getProtectionDomain().getCodeSource().getLocation();
        URL resourceURL = classLoc.toString().endsWith(".jar")
                ? new URL("jar:" + URLDecoder.decode(classLoc.toString(), "UTF-8") + "!/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat")
                : new URL(URLDecoder.decode(classLoc.toString(), "UTF-8") + "/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat");
        datUrls.add(resourceURL);
     }

     // Use the Log4J2 PluginCache to build a merged Log4j2Plugins.dat
     File mergedDatFile = new File("target/Log4j2Plugins.dat");
     try (FileOutputStream fo = new FileOutputStream(mergedDatFile)) {
        org.apache.logging.log4j.core.config.plugins.processor.PluginCache pc = new org.apache.logging.log4j.core.config.plugins.processor.PluginCache();
        pc.loadCacheFiles(datUrls.elements());
        pc.writeCache(fo);
     }

     // Replace the default Log4j2Plugins.dat if present
     ja.delete("/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat");
     ja.addAsManifestResource(mergedDatFile, "org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat");

  } catch (Exception ex) {
     ex.printStackTrace(System.err);
  }
}

To run:

JavaArchive ja = ShrinkWrap.create(JavaArchive.class, "my-test.jar");
...
mergeLog4J2Log4j2PluginsFile(ja, org.apache.logging.log4j.core.config.plugins.processor.PluginCache.class, MyCustomPlugin.class);