log4j2 configuration will not load custom pattern

2019-01-20 12:02发布

问题:

I am trying to create a custom pattern converter for log4j 2.0, but am having issues getting my log4j configuration to recognize the pattern. Here is the custom converter:

package com.test.log4j.plugins;

import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.pattern.ConverterKeys;
import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;

@Plugin(name="MarkerNamePatternConverter", category="Converter")
@ConverterKeys({"markername"})
public class MarkerNamePatternConverter extends LogEventPatternConverter {

    public static MarkerNamePatternConverter newInstance(final String[] options) {
        return new MarkerNamePatternConverter("markername", "markername");
    }

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

    @Override
    public void format(LogEvent event, StringBuilder toAppendTo) {
        Marker marker = event.getMarker();
        if (marker != null) {
            // MarkerPatternConverter appends Marker.toString()
            // which includes the parents of the marker.  We just
            // want the marker's name
            toAppendTo.append(marker.getName());
        }
    }
}

And here is my log4j configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace" packages="com.test.log4j.plugins">
  <Appenders>
    <Console name="console" target="SYSTEM_OUT">
      <PatternLayout pattern=" %-6level %markername  %d{YYYY-MM-dd HH:mm:ss}  %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="debug">
      <AppenderRef ref="console"/>
    </Root>
  </Loggers>
</Configuration>

Note that I have included the package which contains the custom converter in my configuration, the lack of which seems to be a common cause of issues when using custom plugins.

When test code is executed, the configuration status output does not indicate that the plugin is loaded or found, and log4j treats the %markername as if it is the "%marker" conversion pattern followed by "name". For example,

Marker marker = MarkerManager.getMarker("TEST");
log.info(marker, "test message");

produces the following output:

INFO   TESTname  2014-07-23 14:47:57  test message

I tried changing the conversion key a value that did not start with a standard conversion pattern, e.g. "fmarker", and when executed log4j produces the following error:

2014-07-23 14:44:55,814 ERROR Unrecognized format specifier [fmarker]
2014-07-23 14:44:55,816 ERROR Unrecognized conversion specifier [fmarker] starting at     position 18 in conversion pattern.
INFO   %fmarker  2014-07-23 14:44:55  test message

Documentation indicates that plugins are gathered at build time rather than runtime, but I haven't found anything that indicates that I need to do something specific to get my custom converter to be found other than to:

  1. Annotate it with @Plugin and @ConverterKeys
  2. Specify the plugin's category to be a "Converter"
  3. Include a static "newInstance(String[])" method
  4. Implement the "format" method
  5. Specify the plugin package with the configuration's "packages" parameter.

There was documentation for a Maven plugin, but my simple test is just a basic Java project developed in Eclipse.

Any ideas on what I am doing wrong?

回答1:

To make a long story short, since version 2.0-rc2, the packages attribute does not work any more. Instead, there is an annotation processor in log4j-core that will (should?) run during the build and will generate a metadata file for your custom plugins in your jar file. When log4j2 starts it will look for the metadata file in all jar files and quickly discover all available plugins.

The annotation processor works when compiling with Maven or with plain javac, but it may not work well when compiling in Eclipse. You need to enable annotation processing with right-click on a project > Properties > Java Compiler > Annotation Processing.

Still, I am not 100% sure this will work from Eclipse. For now, one alternative is to build your custom plugin with Maven.

I will try to make the packages attribute work again in an upcoming release.

This issue is tracked here: https://issues.apache.org/jira/browse/LOG4J2-741

UPDATE (7/28) This is fixed in trunk and will be included in the 2.0.1 release.



回答2:

I spent a couple of hours struggling with this one as well...

Apparently, it's all about class loading!

Use this trick:

Run your app using -verbose:class (it will print all the classes loaded by the JVM by their order)

e.g.

java -verbose:class -cp <your_jar> <your_main_class> ...

Search for the log4j2 converter class; in your case, it should look like this:

[Loaded com.test.log4j.plugins.MarkerNamePatternConverter from jar:file: ...]     

You'll probably note that the converter class is loaded relatively late (I assume after the log4j2 plugins are supposed to get loaded).

To fix this, you can try one of the following:

  1. Load the converter class explicitly, i.e. Class.forName(...)
  2. Change the converter class location: put it next to your main class or underneath it (in terms of package hierarchy)

I tried both of these options - the second one worked for me!

Goodluck