如何防止 sysout 和 syserr 流混合?

发布于 2024-10-03 14:39:46 字数 1174 浏览 1 评论 0原文

在我的代码库中(非常简化)如下:

public static void main (String[] args) {
   System.out.println("Starting application");
   try {
      System.out.println("About to validate");
      validate(args);
   catch (Exception e) {
      e.printStackTrace();
   }
}

public static void validate(String[] args) {
   System.out.println("Your first arg is " + args[0]);
   if (someProblemWith(args)) {
      System.out.println("Your args are wrong.  It should be: ...");
      throw new BadArgsException(e);
   }
}

效果很好。请注意,上面的示例代码是人为的,只是为了在异常和堆栈跟踪打印之前显示多个日志语句。这通常意味着我的最后一个日志记录语句在堆栈跟踪输出的中间丢失了。有没有一种优雅的方法来要求 e.printStackTrace() 语句等待 System.out 完成其工作?我本质上是在寻找堆栈跟踪作为发生错误时最后打印的内容。这是我上面的程序的示例输出:

 java.lang.Throwable
 ....
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 Your args are wrong.  It should be: ...
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:56)

In my code base is the (very simplified) following:

public static void main (String[] args) {
   System.out.println("Starting application");
   try {
      System.out.println("About to validate");
      validate(args);
   catch (Exception e) {
      e.printStackTrace();
   }
}

public static void validate(String[] args) {
   System.out.println("Your first arg is " + args[0]);
   if (someProblemWith(args)) {
      System.out.println("Your args are wrong.  It should be: ...");
      throw new BadArgsException(e);
   }
}

Which works fine. Note that my example code above is contrived and simply meant to show multiple log statements prior to exception and stack trace printing. This often means that my last logging statement is lost in the middle of the stack trace output. Is there an elegant way to ask the e.printStackTrace() statement to wait until the System.out has finished its work? I'm essentially looking for the stacktrace to be the very last thing printed when an error occurs. Here's a sample output of my program above:

 java.lang.Throwable
 ....
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 Your args are wrong.  It should be: ...
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:56)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

困倦 2024-10-10 14:39:47

您看到在 System.out.println() 语句之间打印堆栈跟踪的原因是因为 System.out 已被缓冲,而 System.err (由堆栈跟踪使用)是无缓冲的。

如果您希望文本按照事情发生的确切顺序显示,则需要“取消缓冲”System.out。最简单的方法是也只使用 System.err 代替 System.out

否则,请在 catch 子句中发生堆栈跟踪之前调用 System.out.flush()

选项 2:使用 Logger 类。

选项 3:实现您自己的“缓冲区”。换句话说,首先将所有内容写入您自己的缓冲区,包括堆栈跟踪(使用 .toString() 或您希望的任何方式),然后在 catch 中刷新您自己的缓冲区。 (这有点多余,因为无论如何您都可以刷新 System.out)。

-=-

来自评论

当然。 Logger 类可用于创建更强大、更详细的日志记录体验。这通常是在应用程序中完成的操作。 Logger 类的实例是从 Logger 类(它是单例)中获取的,并将要使用的类作为参数。然后,您可以使用 .log() 方法将消息记录到其中。 Logger 类的好处是您可以在其上设置级别(例如 DEBUG、WARN...),然后您就可以仅过滤/显示您想要的内容。然后,“日志”消息会以统一的方式显示在控制台中,通常格式为:

2010-11-23 14:45:32,032 DEBUG [MyClass] Your message

以上格式来自log4j,但您可以使用标准 Java Logger。输出应该类似,也许少一点。但我确信它可以配置。

The reason you are seeing the stack trace being printed between the System.out.println() statements, is because System.out is buffered, while System.err (used by stack trace) is unbuffered.

If you want the text to be displayed in the exact order in which things are happening, you need to "unbuffer" the System.out. The simplest way is to also just use System.err there instead of System.out.

Otherwise, call System.out.flush() before your stack traces happen in the catch clauses.

Option 2: Use the Logger class.

Option 3: Implement your own "buffer". In other words, first write everything to your own buffer, including the stack traces (using .toString() or however you wish) and then in the catch flushing you own buffer. (This is kind of redundant since you can just flush the System.out anyway).

-==-

FROM COMMENT

Sure. The Logger class can be used to create a much more robust and detailed logging experience. This is typically what is done in applications. An instance of the Logger class is grabbed from the Logger class (it is a singleton), taking as parameter the class from which is will be used. Then you log messages to it by using the .log() method. The nice thing about the Logger class is that you can set levels on it (example DEBUG, WARN...) and you are then able to filter / display only what you want. The "log" messages are then displayed in a uniform way in the console, typically in the format of:

2010-11-23 14:45:32,032 DEBUG [MyClass] Your message

The above format is from log4j, but you can use the standard Java Logger. The output should be similar, maybe a bit less. But I'm sure it can be configured.

兲鉂ぱ嘚淚 2024-10-10 14:39:47

调用 e.printStackTrace(System.out);。或者,如果您仅需要它进行调试,则可以将进程的输出和错误与命令行分开: .... 1>output.log 2>error.log

Call e.printStackTrace(System.out);. Or, if you need it for debugging only, you can separate the process' output and error from the command line: .... 1>output.log 2>error.log

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文