I've read every article I could find on using log4j2 with TestNG and, in fact, am using the code for ReporterAppender that I found on SO. Unfortunately, I can't seem to get it to work. I'm getting two very vague errors that I've also researched on this site to no avail:
- 2017-01-05 11:49:29,743 main ERROR Error processing element ReporterAppender ([Appenders: null]): CLASS_NOT_FOUND
- 2017-01-05 11:49:29,866 main ERROR Unable to locate appender "Reporter" for logger config "root"
As you can probably surmise from the format of these errors, I have multiple appenders configured. My console appender and file appender are working beautifully. It's just the one for the TestNG Reporter that I can't make work. Based on that as well as info in the trace output, I'm confident it's finding my log4j2.xml file. I also tried commenting out the configuration lines for the ReporterAppender and the errors went away. However, just like the person in the original post, I want the TestNG report info in my log4j logs. I suspect the problem is in the log4j2.xml file. And, to make matters worse, I'm relatively new to Java. Can anyone shed some light on this? I've wasted far too much time trying to get this to work and am about ready to give up. Log4j2 appears to be very powerful but has a very steep learning curve. Any help would be greatly appreciated! Thanks in advance.
Log4j2.xml (Modified):
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace" packages="com.xyz.ReporterAppender">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level: %msg%n"/>
</Console>
<File name="FileAppender" fileName="../logs/TestNG_${date:yyyyMMdd_HHMMSS}.log" append="false">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level: %msg%n"/>
</File>
<Reporter name="TestReporter">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level: %msg%n"/>
</Reporter>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="Console"/>
<AppenderRef ref="FileAppender"/>
<AppenderRef ref="TestReporter"/>
</Root>
</Loggers>
</Configuration>
ReporterAppender.java:
package com.xyz.ReporterAppender;
import java.io.Serializable;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
import org.apache.logging.log4j.core.layout.AbstractStringLayout;
import org.testng.Reporter;
@Plugin(name="Reporter", category ="Core", elementType="appender", printObject=true)
public class ReporterAppender extends AbstractAppender {
private ReporterAppender(final String name, final Layout layout) {
super(name, null, layout, false);
}
@Override
public void append(final LogEvent event) {
final Layout<? extends Serializable> layout = getLayout();
if (layout != null && layout instanceof AbstractStringLayout) {
Reporter.log(((AbstractStringLayout) layout).toSerializable(event));
} else {
Reporter.log(event.getMessage().getFormattedMessage());
}
}
@PluginFactory
public static ReporterAppender createAppender(
@PluginAttribute("name") @Required(message = "A name for the Appender must be specified") final String name,
@PluginElement("Layout") Layout<? extends Serializable> layout) {
return new ReporterAppender(name, layout);
}
}
LoggingTest.java:
package com.xyz.tests;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.testng.annotations.Test;
public class LoggingTest {
private static final Logger logger = LogManager.getLogger();
@Test()
public void Test() {
logger.info("Begin test.");
logger.debug("Debug message");
logger.error("Error message.");
logger.trace("Trace message.");
}
}