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

Posted

技术标签:

【中文标题】如何让 log4j syslog appender 在一行中写入堆栈跟踪?【英文标题】:How to make log4j syslog appender write a stack trace in one line? 【发布时间】:2016-07-20 16:43:17 【问题描述】:

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

有没有办法配置它,以便整个堆栈跟踪将作为一行而不是多行?

【问题讨论】:

我不确定你能做到这一点,因为我不相信实际上是 log4j 正在执行堆栈跟踪写入。您可以将其写入字符串并删除回车符。 模式布局怎么样? 看起来 @davidhxx 回答了你的问题,但我的意思是我的印象是 Log4J 和所有日志记录工具都只是使用 Throwable.printStackTrace() 来输出堆栈跟踪,在这种情况下您可能无法轻松更改格式。但是,根据下面的答案,Log4J 似乎有某种规定来处理它,我猜这是使用覆盖的 printStackTrace() 调用之一将值写入流/写入器,以便您可以更改它. 【参考方案1】:

我正在使用以下 log4j2 配置,它可以很好地发送到 syslog,并且不需要更改代码即可将所有这些异常转换为字符串。它只是用异常管道替换默认的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 %throwableseparator(|)"></PatternLayout>
    </Syslog>

【讨论】:

很好的解决方案。也许您应该考虑更换恰好为此设计的 \u2028 管道。 明确一点,这就是您在 PatternLayout 中使用 \u2028 的方式(因为它需要 XML 转义码;\u 代码不起作用):%throwableseparator(&amp;#8232;)【参考方案2】:

Log4j2

见james' answer。

Log4j v1

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

如果这是您要解决的问题,那么james mentioned 最好的方法是使用带有%throwable 转换字符的模式布局。他记录了如何为 log4j2 做到这一点。对于 log4j1,它需要 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>

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

如果您真的希望堆栈跟踪位于一行,快速解决方法是将上述示例与%throwableshort%throwable1 一起使用,这将只包括堆栈跟踪的第一行。

如果您希望将整个堆栈跟踪放在一行中,您可能更喜欢使用自定义 ThrowableRenderer 作为 proposed by davidxxx。 (请注意,这仍然会将格式化的日志与堆栈跟踪分开发送到 syslog,因此为避免您可以将此解决方案与上述解决方案结合使用。)

例如:

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"/>

【讨论】:

在 log4j 1.x 中使用 EnhancedPatternLayout 和 %throwable 似乎没有任何用处。它仍然在多行中打印堆栈跟踪。你为什么说这行得通? 此解决方案(您建议的)是否特定于附加程序?应该不会吧?我正在使用 ConsoleAppender。 在logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/… 中,我没有看到任何建议支持在一行中显示堆栈跟踪。 @peter.petrov 很好的反馈,谢谢!我已经更新了我的答案,希望能更清楚。【参考方案3】:

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

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

ThrowableRenderer 您可以自定义 Throwable 实例转换为 String 的方式 在被记录之前。这是通过指定 ThrowableRenderer 来完成的。 语法是: log4j.throwableRenderer=fully.qualified.name.of.rendering.class log4j.throwableRenderer.paramName=paramValue 如中, log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer

【讨论】:

谢谢,忘了提到我在 JBOSS Fuse 中使用它,所以我只能在代码方面做的非常有限,只能更改 Log4J 属性。有没有我可以使用的渲染器? 我不明白为什么您不能创建自己的渲染类并将其放入 JBoss 的类路径位置(例如 lib 目录)。 JBoss 有这个目录:common/lib。 JBoss的导火索有没有?有两个渲染器,但它们不能满足您的需求。 DefaultThrowableRenderer 和 EnhancedThrowableRenderer。 虽然这可行,但它仍会将日志消息和堆栈跟踪作为两个单独的系统日志消息发送。 @bmaupin 你确定吗?那是遗憾。无论您和 James 提出什么解决方案,显然都更好,因为它避免了在 log4j 配置文件之外创建一个类。 @davidxxx 无论 bmaupin 建议什么听起来不错,但不起作用。至少对我来说它不起作用。请参阅我添加到他的答案中的 cmets。你有什么主意吗?另见:***.com/questions/63623141/…你能提供一些想法吗?【参考方案4】:

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

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

【讨论】:

这不是传统的记录方式。您可以忘记执行 log.error(e) 并调用经典和常见的共享方式。保持共同共享的良好实践在软件开发中很重要。

以上是关于如何让 log4j syslog appender 在一行中写入堆栈跟踪?的主要内容,如果未能解决你的问题,请参考以下文章

Log4J 2 Syslog Appender 无法正常工作

log4j2 - Syslog 附加程序和 PatternLayout

Mac 上的 Log4j2 Syslog Appender 格式

Log4j2 Syslog Appender 添加垃圾字段

Weblogic 12C 将日志发送到 syslog

Log4net:SysLog Appender 示例