[
https://issues.apache.org/jira/browse/LOG4J2-2874?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Volkan Yazici updated LOG4J2-2874:
----------------------------------
Description:
Upon further investigation on [Fred Eisele's question in the mailing
list|http://mail-archives.apache.org/mod_mbox/logging-log4j-user/202006.mbox/%3CCAJGQK3M63cx37tfLUSB0X9x3U8PmvUdDOigX-kUTMs6r2nP6hg%40mail.gmail.com%3E],
I figured {{Layout}}'s way of handling {{Message}}'s of type
{{StringBuilderFormattable}} is broken when the actual message is wrapped by
some other message. Consider the following Java code:
{code:java}
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.util.StringBuilderFormattable;
import org.junit.Test;
public class TraceExitTest {
@Test
public void test() {
System.setProperty(
"log4j.configurationFile",
"/tmp/traceExit.xml");
Logger logger = LogManager.getLogger("TraceExit");
int result = logger.traceExit(
new CustomMessage("Volkan was here"),
1);
logger.warn("result = %d", result);
}
private static final class CustomMessage
implements Message, StringBuilderFormattable {
private final String text;
private CustomMessage(String text) {
this.text = text;
}
@Override
public String getFormattedMessage() {
throw new UnsupportedOperationException();
}
@Override
public String getFormat() {
return "";
}
@Override
public Object[] getParameters() {
return new Object[0];
}
@Override
public Throwable getThrowable() {
return null;
}
@Override
public void formatTo(StringBuilder buffer) {
buffer.append(text);
}
}
}
{code}
In combination with the following {{/tmp/traceExit.xml}}:
{code:xml}
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="ERROR">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%msg%n%throwable"/>
</Console>
</Appenders>
<Loggers>
<Root level="TRACE">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
{code}
Log4j produces the {{An exception occurred processing Appender Console
java.lang.UnsupportedOperationException}} error message. In the case of
{{PatternLayout}}, it handles {{StringBuilderFormattable}} with a simple
{{instanceof}} check -- just like any other layout. Though check out the
following {{AbstractLogger#traceExit()}} implementation:
{code:java}
@Override
public <R> R traceExit(final Message message, final R result) {
// If the message is null, traceEnter returned null because ...
if (message != null && isEnabled(Level.TRACE, EXIT_MARKER, message, null)) {
logMessageSafely(...,
flowMessageFactory.newExitMessage(result, message), null);
}
return result;
}
{code}
{{CustomMessage}} gets wrapped by a
{{DefaultFlowMessageFactory.SimpleExitMessage}} invalidating the {{instanceof
StringBuilderFormattable}} check.
One can fix the existing layouts by improving the check as follows:
{code:java}
final boolean formattable =
logEvent.getMessage() instanceof StringBuilderFormattable ||
(logEvent.getMessage() instanceof FlowMessage && ((FlowMessage)
logEvent.getMessage()) instanceof StringBuilderFormattable);
{code}
Though I have my doubts if this will cover every single case.
was:
Upon further investigation on [Fred Eisele's question in the mailing
list|http://mail-archives.apache.org/mod_mbox/logging-log4j-user/202006.mbox/%3CCAJGQK3M63cx37tfLUSB0X9x3U8PmvUdDOigX-kUTMs6r2nP6hg%40mail.gmail.com%3E],
I figured {{Layout}}s way of handling {{Message}}s of type
{{StringBuilderFormattable}} is broken when the actual message is wrapped by
some other message. Consider the following Java code:
{code:java}
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.util.StringBuilderFormattable;
import org.junit.Test;
public class TraceExitTest {
@Test
public void test() {
System.setProperty(
"log4j.configurationFile",
"/tmp/traceExit.xml");
Logger logger = LogManager.getLogger("TraceExit");
int result = logger.traceExit(
new CustomMessage("Volkan was here"),
1);
logger.warn("result = %d", result);
}
private static final class CustomMessage
implements Message, StringBuilderFormattable {
private final String text;
private CustomMessage(String text) {
this.text = text;
}
@Override
public String getFormattedMessage() {
throw new UnsupportedOperationException();
}
@Override
public String getFormat() {
return "";
}
@Override
public Object[] getParameters() {
return new Object[0];
}
@Override
public Throwable getThrowable() {
return null;
}
@Override
public void formatTo(StringBuilder buffer) {
buffer.append(text);
}
}
}
{code}
In combination with the following {{/tmp/traceExit.xml}}:
{code:xml}
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="ERROR">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%msg%n%throwable"/>
</Console>
</Appenders>
<Loggers>
<Root level="TRACE">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
{code}
Log4j produces the {{An exception occurred processing Appender Console
java.lang.UnsupportedOperationException}} error message. In the case of
{{PatternLayout}}, it handles {{StringBuilderFormattable}} with a simple
{{instanceof}} check -- just like any other layout. Though check out the
following {{AbstractLogger#traceExit()}} implementation:
{code:java}
@Override
public <R> R traceExit(final Message message, final R result) {
// If the message is null, traceEnter returned null because ...
if (message != null && isEnabled(Level.TRACE, EXIT_MARKER, message, null)) {
logMessageSafely(...,
flowMessageFactory.newExitMessage(result, message), null);
}
return result;
}
{code}
{{CustomMessage}} gets wrapped by a
{{DefaultFlowMessageFactory.SimpleExitMessage}} invalidating the {{instanceof
StringBuilderFormattable}} check.
One can fix the existing layouts by improving the check as follows:
{code:java}
final boolean formattable =
logEvent.getMessage() instanceof StringBuilderFormattable ||
(logEvent.getMessage() instanceof FlowMessage && ((FlowMessage)
logEvent.getMessage()) instanceof StringBuilderFormattable);
{code}
Though I have my doubts if this will cover every single case.
> StringBuilderFormattable check failure in layouts due to wrapped Message
> ------------------------------------------------------------------------
>
> Key: LOG4J2-2874
> URL: https://issues.apache.org/jira/browse/LOG4J2-2874
> Project: Log4j 2
> Issue Type: Bug
> Reporter: Volkan Yazici
> Priority: Major
>
> Upon further investigation on [Fred Eisele's question in the mailing
> list|http://mail-archives.apache.org/mod_mbox/logging-log4j-user/202006.mbox/%3CCAJGQK3M63cx37tfLUSB0X9x3U8PmvUdDOigX-kUTMs6r2nP6hg%40mail.gmail.com%3E],
> I figured {{Layout}}'s way of handling {{Message}}'s of type
> {{StringBuilderFormattable}} is broken when the actual message is wrapped by
> some other message. Consider the following Java code:
> {code:java}
> import org.apache.logging.log4j.message.Message;
> import org.apache.logging.log4j.util.StringBuilderFormattable;
> import org.junit.Test;
> public class TraceExitTest {
> @Test
> public void test() {
> System.setProperty(
> "log4j.configurationFile",
> "/tmp/traceExit.xml");
> Logger logger = LogManager.getLogger("TraceExit");
> int result = logger.traceExit(
> new CustomMessage("Volkan was here"),
> 1);
> logger.warn("result = %d", result);
> }
> private static final class CustomMessage
> implements Message, StringBuilderFormattable {
> private final String text;
> private CustomMessage(String text) {
> this.text = text;
> }
> @Override
> public String getFormattedMessage() {
> throw new UnsupportedOperationException();
> }
> @Override
> public String getFormat() {
> return "";
> }
> @Override
> public Object[] getParameters() {
> return new Object[0];
> }
> @Override
> public Throwable getThrowable() {
> return null;
> }
> @Override
> public void formatTo(StringBuilder buffer) {
> buffer.append(text);
> }
> }
> }
> {code}
> In combination with the following {{/tmp/traceExit.xml}}:
> {code:xml}
> <?xml version="1.0" encoding="UTF-8"?>
> <Configuration status="ERROR">
> <Appenders>
> <Console name="Console" target="SYSTEM_OUT">
> <PatternLayout pattern="%msg%n%throwable"/>
> </Console>
> </Appenders>
> <Loggers>
> <Root level="TRACE">
> <AppenderRef ref="Console"/>
> </Root>
> </Loggers>
> </Configuration>
> {code}
> Log4j produces the {{An exception occurred processing Appender Console
> java.lang.UnsupportedOperationException}} error message. In the case of
> {{PatternLayout}}, it handles {{StringBuilderFormattable}} with a simple
> {{instanceof}} check -- just like any other layout. Though check out the
> following {{AbstractLogger#traceExit()}} implementation:
> {code:java}
> @Override
> public <R> R traceExit(final Message message, final R result) {
> // If the message is null, traceEnter returned null because ...
> if (message != null && isEnabled(Level.TRACE, EXIT_MARKER, message,
> null)) {
> logMessageSafely(...,
> flowMessageFactory.newExitMessage(result, message), null);
> }
> return result;
> }
> {code}
>
> {{CustomMessage}} gets wrapped by a
> {{DefaultFlowMessageFactory.SimpleExitMessage}} invalidating the {{instanceof
> StringBuilderFormattable}} check.
> One can fix the existing layouts by improving the check as follows:
> {code:java}
> final boolean formattable =
> logEvent.getMessage() instanceof StringBuilderFormattable ||
> (logEvent.getMessage() instanceof FlowMessage &&
> ((FlowMessage) logEvent.getMessage()) instanceof StringBuilderFormattable);
> {code}
> Though I have my doubts if this will cover every single case.
--
This message was sent by Atlassian Jira
(v8.3.4#803005)