Log4j2's FailoverAppender Error: appender Fail

2019-04-07 20:22发布

问题:

When I compile my spring 3.2.9 web application using log4j 2.1, this error appears in the console:

2015-02-02 12:08:25,213 ERROR appender Failover has no parameter that matches element Failovers

What I understand is that the element "Failovers" does not exist inside the element "Failover", right? Why would this happen? I don't see whats wrong since I have the same configuration as the log4j2 manual.

I have this configuration in my log4j2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration name="vcr-log4j2-config" status="debug">
    <Appenders>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout>
                <Pattern>[%d{ISO8601}] %c [%C{1}] - %p: %m%n</Pattern>
            </PatternLayout>
        </Console>

        <Syslog name="SYS_LOG" host="test_server.com" port="514" 
                protocol="UDP" facility="LOCAL7">
        </Syslog>

        <RollingFile name="backupApp"
            fileName="C:/backup.log"
            filePattern="C:/backup-%d{yyyy-MM-dd_HH-mm}.log.gz">
            <PatternLayout>
                <Pattern>[%d{ISO8601}] [%c] - %p: %m%n</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1"
                    modulate="true" />
            </Policies>
        </RollingFile>

        <Failover name="FAILOVER" primary="SYS_LOG">
            <Failovers>
                <AppenderRef ref="backupApp"/>
            </Failovers>
        </Failover>     
    </Appenders>

    <Loggers>
        <Logger name="com.test.util.CustomLogger" level="info" additivity="false">
            <AppenderRef ref="SYS_LOG" />
            <AppenderRef ref="STDOUT" />
        </Logger>

        <Logger name="STDOUT" level="info" additivity="false">
            <AppenderRef ref="STDOUT" />
        </Logger>

        <Root level="info">
            <AppenderRef ref="STDOUT" />
            <AppenderRef ref="LOG" />
        </Root>

        <Root level="error">
            <AppenderRef ref="FAILOVER"/>
        </Root>
    </Loggers>
</Configuration>

Thanks for the help.

回答1:

What I have seen while debugging is the PluginBuilder#verifyNodeChildrenUsed() method is called to, you would expect, verify that the child elements of the Node are correct. As I describe below, this method name does not match the behaviour.

In the case of a Failover appender, the plugin type is: (btw, the extra "==" at "isDeferChildren" is just in the toString() implementation and does not affect the test.)

PluginType [pluginClass=class org.apache.logging.log4j.core.appender.FailoversPlugin, key=failovers, elementName=failovers, isObjectPrintable=false, isDeferChildren==false, category=core]

The implementation of this method:

private void verifyNodeChildrenUsed() {
    final List<Node> children = node.getChildren();
    if (!(pluginType.isDeferChildren() || children.isEmpty())) {
        for (final Node child : children) {
            final String nodeType = node.getType().getElementName();
            final String start = nodeType.equals(node.getName()) ? node.getName() : nodeType + ' ' + node.getName();
            LOGGER.error("{} has no parameter that matches element {}", start, child.getName());
        }
   }
}

When the nodeType is the FailoversPlugin class (see above), the node type is "appender" but the name is "Failovers". So the test of equality produces the string "appender Failovers".

What I haven't dug into fully is WHY this method is called such that if the node is not empty and the property of deferring is false, the error message MUST be displayed. It seems to me that the logic here is dependent on something up-the-stack and tracing through this is cumbersome.

What I'd really like to do is ask the developer responsible what's the intention, because it's not clear to me that the behaviour is correct. Well, obviously that's true in this case. :S



回答2:

This is a bug in log4j. I've pointed out the error in the issue linked to by @Deses. For the time-being, here's a workaround:

/**
 * Avoids a bug in log4j, whereby plugins that produce an array (e.g. {@linkplain FailoversPlugin})
 * cause an error to be logged.
 * <p>
 * To use, instead of this:
 * <pre>
 * &lt;Failover name="MyAppender" primary="xxx">
 *   &lt;Failovers>
 *     &lt;AppenderRef ref="fallback1"/>
 *     &lt;AppenderRef ref="fallback2"/>
 *   &lt;/Failovers>
 * &lt;/Failover>
 * </pre>
 * do this:
 * <pre>
 * &lt;Failover name="MyAppender" primary="xxx">
 *   &lt;Fallback ref="fallback1"/>
 *   &lt;Fallback ref="fallback2"/>
 * &lt;/Failover>
 * </pre>
 */
@Plugin(name="Fallback", category=Node.CATEGORY, elementType="Failovers")
public class Fallback {

    private Fallback(){}

    @PluginFactory
    public static String createFallbackRef(@PluginAttribute("ref") @Required String ref) {
        return ref;
    }

}

Just stick this on your compile and runtime classpaths, and make sure annotation processing is enabled.



回答3:

For anyone that runs into this problem, it's a bug in log4j2.

I ran into this JIRA issue and found this commentary in its xml config file:

<!-- set status below to FATAL to suppress a bug in log4j2: "ERROR appender Failover has no parameter that matches element Failovers" -->
<!--  other working value for status is "warn" -  -->

Not much else to do.



回答4:

I had a similar issue and i had commented the failover tags in Log4j xml and all my logs are getting created now



回答5:

in my case, you should add ignoreExceptions filed on both primary and failovers.

`<Console name="Console-Appender" target="SYSTEM_OUT" ignoreExceptions="false">
            <PatternLayout>
                <pattern>${log-pattern}</pattern>
            </PatternLayout>
</Console>`