本文介绍了使用log4j2 API在EAR中未检测到自定义插件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将EAR应用程序从log4j迁移到log4j2.我有一些类可以在不同的EAR罐中扩展追加器,过滤器和布局,现在,我将它们转换为插件.这意味着我在多个jar(假设3个jar)中有自定义插件.

我没有在log4j2.xml中使用packages属性,而是通过使用指向EAR META-INFlog4j2.xml位置的Dlog4j.configurationFile JVM参数来初始化日志记录系统.

在所有三个jar项目中添加以下插件均无效.

<plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <executions>
                <execution>
                    <id>log4j-plugin-processor</id>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                    <phase>process-classes</phase>
                    <configuration>
                        <proc>only</proc>
                        <annotationProcessors>
                            <annotationProcessor>org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor</annotationProcessor>
                        </annotationProcessors>
                    </configuration>
                </execution>
            </executions>
        </plugin>

图案布局:在以下模式布局中,e是自定义模式,在该自定义模式中编写了一个自定义模式转换器插件来转换此字符串.

<Pattern>%d %-5p [%c{1}] [EventId: %e] [%t] %m%n</Pattern>

用于上述模式布局的自定义转换器插件(在jar1中):

jar1在org.apache..文件夹的META-INF下具有Log4J2Plugins.dat文件.

@Plugin(name = "EventPatternConverter", category = "Converter")
@ConverterKeys({"e"})

public class EventPatternConverter extends LogEventPatternConverter {

protected EventPatternConverter(String name, String style) {
    super(name, style);
}

public static EventPatternConverter newInstance(String[] options) {
  return new EventPatternConverter("e", "e");
}

@Override
public void format(LogEvent event, StringBuilder toAppendTo) {
    String eventId= "";
    // Append empty string (OR) value
    toAppendTo.append(eventId);
  }
}

但是,我收到以下错误

ERROR Unrecognized format specifier [e]

就算我在其余的自定义插件中都得到了invalid element,也没有一个自定义插件被识别出来,其余的自定义插件都可以在jar2,jar3中使用,并且都具有Log4J2Plugins.dat文件.

ERROR File contains an invalid element or attribute "TestFilter"

我在EAR中使用log4j-api-2.4.jarlog4j-core-2.4.jarlog4j-jcl-2.4.jarlog4j-web-2.4.1.jarcommons-logging-1.1.1.jar罐子.

我已经定义了一个自定义模式转换器插件,并希望此转换器可应用于所有模式布局,包括使用<patternlayout>定义的默认模式布局.是这样吗?

如果是的话,如果有人遇到此问题,请提供帮助,如果我在定义自定义插件时出错,请指导我,因为它们都没有从EAR中的jar中被检测到.

解决方案

在编译自定义插件时,Log4J pom.xml定义了一个插件,该插件会自动在文件META-INF/org/apache/logging/log4j中生成缓存数据/core/config/plugins/Log4j2Plugins.dat您可以在Maven项目的目标/类下看到它.

log4j-core-2.x.x.jar还包含一个Log4j2Plugins.dat,用于定义其缓存数据.

问题是使用ShrinkWrap测试EAR时会创建单个JAR,通常将log4j-core-2.xxjar Log4j2Plugins.dat添加到测试JAR中,因为它很可能是类路径中的第一个. /p>

这意味着您的自定义插件缓存丢失.

使用ShrinkWrap的解决方案是创建一个新的Log4j2Plugins.dat,将所有必需的自定义插件缓存文件与内核合并,然后将其添加到JAR中.

以下功能可以实现...

private static void mergeLog4J2Log4j2PluginsFile(JavaArchive ja, Class... uniqueJARClasses) {
  // @Author: Johnathan Ingram <[email protected]>
  // 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);
  }
}

以您的示例运行:

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

I am migrating an EAR application from log4j to log4j2. I had classes extending appenders, filters, layouts in different jars of EAR and now, I have converted those to plugins. This means I have custom plugins in more than one jar (assume 3 jars).

I am not using packages attribute in log4j2.xml and am initializing the logging system by using Dlog4j.configurationFile JVM argument pointing to log4j2.xml location in META-INF of EAR.

Adding the below plugin in all the three jar projects did not work .

<plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <executions>
                <execution>
                    <id>log4j-plugin-processor</id>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                    <phase>process-classes</phase>
                    <configuration>
                        <proc>only</proc>
                        <annotationProcessors>
                            <annotationProcessor>org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor</annotationProcessor>
                        </annotationProcessors>
                    </configuration>
                </execution>
            </executions>
        </plugin>

Pattern layout:In the below pattern layout, e is the custom pattern where a custom pattern converter plugin is written to convert this string.

<Pattern>%d %-5p [%c{1}] [EventId: %e] [%t] %m%n</Pattern>

Custom converter plugin for the above pattern layout (in jar1):

jar1 has Log4J2Plugins.dat file under META-INF in org.apache.. folder.

@Plugin(name = "EventPatternConverter", category = "Converter")
@ConverterKeys({"e"})

public class EventPatternConverter extends LogEventPatternConverter {

protected EventPatternConverter(String name, String style) {
    super(name, style);
}

public static EventPatternConverter newInstance(String[] options) {
  return new EventPatternConverter("e", "e");
}

@Override
public void format(LogEvent event, StringBuilder toAppendTo) {
    String eventId= "";
    // Append empty string (OR) value
    toAppendTo.append(eventId);
  }
}

But, I am getting the below error

ERROR Unrecognized format specifier [e]

Even, none of the custom plugins are identified as I am getting invalid element for rest of the custom plugins which are all available in jar2, jar3 and they all have Log4J2Plugins.dat file.

ERROR File contains an invalid element or attribute "TestFilter"

I am using log4j-api-2.4.jar, log4j-core-2.4.jar, log4j-jcl-2.4.jar, log4j-web-2.4.1.jar, commons-logging-1.1.1.jar jars in the EAR.

I have defined a custom pattern converter plugin and expecting this converter gets applied to all pattern layout including default pattern layout defined using <patternlayout>. Is this right ?

If yes, the please help if anyone faced this issue and guide me if I am wrong in defining the custom plugin as they are all not getting detected from jars in EAR.

解决方案

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.datYou 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 <[email protected]>
  // 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 using your example:

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

这篇关于使用log4j2 API在EAR中未检测到自定义插件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-21 09:10