Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Log4j2's FailoverAppender Error: appender Failover has no parameter that matches element Failovers

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.

like image 960
Deses Avatar asked Feb 02 '15 11:02

Deses


2 Answers

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

like image 119
Robin Coe Avatar answered Oct 14 '22 10:10

Robin Coe


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.

like image 23
user31601 Avatar answered Oct 14 '22 12:10

user31601