记录 System.out.println 在 JBoss 中迷路

Posted

技术标签:

【中文标题】记录 System.out.println 在 JBoss 中迷路【英文标题】:logging System.out.println getting lost in JBoss 【发布时间】:2017-06-13 19:31:50 【问题描述】:

我正在使用简单的 System.out.printf / System.out.println 语句来执行 JBoss 日志记录(我正在部署到 JBoss EAP 6.2)。我注意到,当发生异常时,我倾向于在抛出异常之前立即丢失println 消息。这使得无法调试异常。

为了验证这一点,我在我的 WAR 中输入了以下代码:

 System.out.println("foo");
 int i = 0; if (i==0) throw new RuntimeException();
 ...

int i = 0; if (i==0) 部分只是为了让编译器静音,否则会抱怨)

确实,当执行此代码时,在服务器的日志文件 (standalone/log/server.log) 中我根本看不到 foo。我看到了异常的报告,但上面什么也没有。

我尝试在循环中打印相同的消息 100 次,明确地执行 System.out.flush() 并在抛出异常之前执行 java.util.concurrent.TimeUnit.MINUTES.sleep(1)。没有任何改变,在server.log 中根本看不到任何输出。仅显示异常跟踪,但其上方没有 foo

我了解 JBoss 将 std:outstd:err 包装到自己的日志框架中,我假设其中涉及某种缓冲导致 System.out.println 输出丢失。

我的 WAR 中没有任何 logging.properties 文件,并且没有修改我正在使用的关于日志记录的标准配置 (standalone-full.xml)。我曾经有一个logging.properties 文件,但我删除了它,因为它导致all System.out.println 丢失,如question 中所述。一旦logging.properties 文件被删除,一些 System.out.println 输出至少会在异常之前看到,即当我最需要它的时候。

我的问题是:

    为什么我会丢失此输出,如何确保 System.out.println 始终包含在 server.log 中? 有哪些技巧可以简化 JBoss 中的日志记录情况?整个事情非常复杂且无证。

【问题讨论】:

我在 JBoss 中部署了多个应用程序。在某些应用程序中,即使我没有使用任何特定的记录器框架并且仅使用 System.out。我从来没有遇到过这样的问题。您可以尝试(远程)在 Eclipse 等 IDE 中调试您的代码吗? 我建议使用带有 logback 或 log4j 的日志框架 SLF4J @RAS 将其标记为 JBoss 6.x(实际上是 6.2)。 @MarcusJuniusBrutus,是的,我也在使用 JBoss 6.x。请尝试在不打印输出的 Eclipse 中调试您的代码。 【参考方案1】:

原来还有一个logging.properties 文件潜伏在周围。删除它后,我可以再次看到 server.log 线索上的所有 System.out.println 消息。我仍然不清楚为什么 logging.properties 文件的存在应该与普通的 STD:OUT 输出混淆。

更新

尝试按照 James R. Perkins 的建议尝试在我的 META-INF 目录中添加一个 jboss-deployment-structure.xml 文件以禁用日志子系统对我的组件的处理并添加以下内容:

<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.1">   
   <deployment>
    <exclusions>
     <module name="org.jboss.logging"/>
     <module name="org.apache.log4j"/>
    </exclusions>
   </deployment>
</jboss-deployment-structure>

……这没用。 System.out.println 输出仍然丢失。所以唯一的解决方法是删除logging.propertieslog4j.xml 文件。感谢 James R. Perkins 建议这实际上可能是 JBoss EAP 6.2.0 中的 bug

【讨论】:

它允许用户在他们的部署中包含他们自己的日志配置。如果您不想删除 logging.properties 文件,您可以添加 jboss-deployment-descriptor.xml 并从处理您的部署中排除日志记录子系统。 @JamesR.Perkins 如果我要“从处理我的部署中排除日志记录子系统”,我还会在server.log 上看到普通的旧 System.out.println 消息吗? 是的。它们包装在记录器中,您的部署将使用服务器级别的记录上下文。 @JamesR.Perkins 添加了jboss-deployment-structure.xml(不是-descriptor,也许这是您评论中的拼写错误?)但没有任何反应(请参阅问题末尾的更新)。 System.out.println 输出仍然丢失。所以唯一的解决方法是删除 log4j.xmllogging.properties 文件。 抱歉打错了,应该是jboss-deployment-structure.xml。我的意思是排除logging 子系统。 &lt;exclude-subsystems&gt;&lt;subsystem name="logging"/&gt;&lt;/exclude-subsystems&gt;docs.jboss.org/author/display/WFLY10/…【参考方案2】:

遇到与操作相同的问题并找到this。它本质上说你应该添加

<console-handler name="STDOUT">
  <level name="INFO"/>
  <formatter>
    <pattern-formatter pattern="%s%E%n"/>
  </formatter>
</console-handler>
<logger category="stdout" use-parent-handlers="false">
  <level name="INFO"/>
  <handlers>
    <handler name="STDOUT"/>
  </handlers>
</logger>

在standalone.xml 或 domain.xml 中或使用 CLI 中的 JBoss 日志记录子系统,您可以这样做:

/subsystem=logging/console-handler=STDOUT:add(level=INFO,formatter="%s%E%n")
/subsystem=logging/logger=stdout:add(level=INFO,handlers=[handler=STDOUT],use-parent-handlers=false)

您可以通过将“stdout”替换为“stderr”来对 STDERR 执行相同的操作。

上面的配置是这样工作的:

添加第二个 ConsoleHandler 这将仅用于调用 System.out.println(...)。 定义标准输出记录器 这无论如何都被 JBoss Logging 使用,但在这里我们明确定义它以便我们可以配置它。 仅将 STDOUT 处理程序添加到标准输出记录器 设置 use-parent-handler=false 这样我们就不会得到重复的日志记录 在第二个 ConsoleHandler 中更改格式化程序模式,这样它就可以简单地按原样打印字符串 - 没有额外的格式化。

这意味着您可能不需要删除您的 logging.properties 和 log4j.xml 文件。希望这能解决问题。

【讨论】:

以上是关于记录 System.out.println 在 JBoss 中迷路的主要内容,如果未能解决你的问题,请参考以下文章

记录器与 System.out.println

log4j 与 System.out.println - 记录器的优势?

java 跳出多层循环

在JAVA中如何跳出当前的多重嵌套循环

system.out.println 在哪里从 JSP 打印?

java中使用System.out.println如何输出多个变量?