如何防止 sysout 和 syserr 流混合?
在我的代码库中(非常简化)如下:
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您看到在 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
,但您可以使用标准 JavaLogger
。输出应该类似,也许少一点。但我确信它可以配置。The reason you are seeing the stack trace being printed between the
System.out.println()
statements, is becauseSystem.out
is buffered, whileSystem.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 useSystem.err
there instead ofSystem.out
.Otherwise, call
System.out.flush()
before your stack traces happen in thecatch
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 thecatch
flushing you own buffer. (This is kind of redundant since you can just flush theSystem.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 theLogger
class is grabbed from theLogger
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 theLogger
class is that you can set levels on it (exampleDEBUG
,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 JavaLogger
. The output should be similar, maybe a bit less. But I'm sure it can be configured.调用 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