如何让 log4j syslog appender 在一行中写入堆栈跟踪?

How to make log4j syslog appender write a stack trace in one line?

我正在使用 log4j syslog appender 并注意到当发生异常时,appender 将堆栈跟踪中的每个条目作为一个新行写入。

有没有办法配置它,使整个堆栈跟踪成为一行而不是多行?

您可以自定义堆栈跟踪的渲染器。 Log4J中有两个可用的ThrowableRendererorg.apache.log4j.spi.ThrowableRenderer接口) 默认使用一个。 因此,使用您希望的格式实现您自己的 ThrowableRenderer,然后在您的配置中设置它。

在 Log4j 1 中,它可以工作。永远不要在 Log42 中尝试。 https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PropertyConfigurator.html

ThrowableRenderer You can customize the way an instance of Throwable is converted to String before being logged. This is done by specifying an ThrowableRenderer. The syntax is: log4j.throwableRenderer=fully.qualified.name.of.rendering.class log4j.throwableRenderer.paramName=paramValue As in, log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer

不是仅仅将异常传递给记录器(例如 log.error(e)),而是首先将堆栈跟踪转换为字符串并记录该字符串。

投票最多的答案to this question有几种简单的方法可以将堆栈跟踪转换为字符串。

我正在使用以下 log4j2 配置,它可以很好地发送到系统日志,并且不需要更改代码即可将所有这些异常转换为字符串。它只是在异常情况下用管道替换默认的 linesep。

    <Syslog name="SYSLOG" host="127.0.0.1" port="515" protocol="TCP" charset="UTF-8"
            immediateFail="false" ignoreExceptions="true" reconnectionDelayMillis="250">
        <PatternLayout pattern="[%d] %-5p %m%n %throwable{separator(|)}"></PatternLayout>
    </Syslog>

Log4j2

Log4j v1

默认情况下,syslog appender 将格式化日志以及堆栈跟踪的每一行作为 syslog 中的单独日志条目发送。因为 syslog 使用 UDP,所以线路可能乱序。

如果这是您要解决的问题,那么 the best way to do this is to use a pattern layout with the %throwable conversion character. He documented how to do it for log4j2. For log4j1, it requires the EnhancedPatternLayout:

<appender name="syslog" class="org.apache.log4j.net.SyslogAppender">
  <param name="SyslogHost" value="127.0.0.1:514"/>
  <layout class="org.apache.log4j.EnhancedPatternLayout">
    <param name="ConversionPattern" value="[%d] %-5p %m%n%throwable"/>
  </layout>
</appender>

注意上述解决方案仍将使用换行符来分隔堆栈跟踪的各个行,但它会解决堆栈跟踪行作为单独发送的问题系统日志中的日志条目。

如果您确实希望在一行中显示堆栈跟踪,一个快速解决方法是将上面的示例与 %throwable{short}%throwable{1} 一起使用,这将仅包含堆栈跟踪的第一行。

如果您希望将整个堆栈跟踪记录在一行中,您可能更愿意使用自定义 ThrowableRenderer 作为 。 (注意这仍然会将格式化的日志与堆栈跟踪分开发送到系统日志,因此可以将此解决方案与上面的解决方案结合使用。)

例如:

import org.apache.log4j.DefaultThrowableRenderer;
import org.apache.log4j.spi.ThrowableRenderer;

import java.util.ArrayList;
import java.util.Arrays;

public class CustomThrowableRenderer implements ThrowableRenderer {
    private final DefaultThrowableRenderer defaultRenderer = new DefaultThrowableRenderer();

    @Override
    public String[] doRender(Throwable throwable) {
        String[] defaultRepresentation = defaultRenderer.doRender(throwable);
        String[] newRepresentation = {String.join("|", Arrays.asList(defaultRepresentation))};

        return newRepresentation;
    }
}

然后在你的 log4j.xml:

<throwableRenderer class="CustomThrowableRenderer"/>