为什么 exception.printStackTrace() 被认为是不好的做法? [英] Why is exception.printStackTrace() considered bad practice?

查看:32
本文介绍了为什么 exception.printStackTrace() 被认为是不好的做法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有很多资料there 这表明打印异常的堆栈跟踪是不好的做法.

There is a lot of material out there which suggests that printing the stack trace of an exception is bad practice.

例如来自 Checkstyle 中的 RegexpSingleline 检查:

E.g. from the RegexpSingleline check in Checkstyle:

此检查可用于[...] 查找常见的不良做法,例如调用 ex.printStacktrace()

This check can be used [...] to find common bad practice such as calling ex.printStacktrace()

但是,我正在努力寻找任何可以提供正当理由的地方,因为堆栈跟踪对于跟踪导致异常的原因肯定非常有用.我知道的事情:

However, I'm struggling to find anywhere which gives a valid reason why since surely the stack trace is very useful in tracking down what caused the exception. Things that I am aware of:

  1. 最终用户不应看到堆栈跟踪(出于用户体验和安全目的)

  1. A stack trace should never be visible to end users (for user experience and security purposes)

生成堆栈跟踪是一个相对昂贵的过程(尽管在大多数例外"情况下不太可能成为问题)

Generating a stack trace is a relatively expensive process (though unlikely to be an issue in most 'exceptional' circumstances)

许多日志框架会为您打印堆栈跟踪(我们的没有,也不,我们无法轻松更改)

Many logging frameworks will print the stack trace for you (ours does not and no, we can't change it easily)

打印堆栈跟踪不构成错误处理.它应该与其他信息记录和异常处理相结合.

Printing the stack trace does not constitute error handling. It should be combined with other information logging and exception handling.

还有什么其他原因可以避免在代码中打印堆栈跟踪?

What other reasons are there for avoiding printing a stack trace in your code?

推荐答案

Throwable.printStackTrace() 将堆栈跟踪写入 System.err PrintStream.System.err 流和 JVM 进程的底层标准错误"输出流可以通过

Throwable.printStackTrace() writes the stack trace to System.err PrintStream. The System.err stream and the underlying standard "error" output stream of the JVM process can be redirected by

  • 调用 System.setErr() 改变了System.err 指向的目的地.
  • 或者通过重定向进程的错误输出流.错误输出流可能被重定向到文件/设备
    • 其内容可能会被人员忽略,
    • 文件/设备可能无法进行日志轮换,因此在归档文件/设备的现有内容之前,需要重新启动进程才能关闭打开的文件/设备句柄.
    • 或者文件/设备实际上丢弃了所有写入它的数据,就像 /dev/null 的情况一样.
    • invoking System.setErr() which changes the destination pointed to by System.err.
    • or by redirecting the process' error output stream. The error output stream may be redirected to a file/device
      • whose contents may be ignored by personnel,
      • the file/device may not be capable of log rotation, inferring that a process restart is required to close the open file/device handle, before archiving the existing contents of the file/device.
      • or the file/device actually discards all data written to it, as is the case of /dev/null.

      从上面推断,调用 Throwable.printStackTrace() 构成有效(不好/很好)的异常处理行为,仅

      Inferring from the above, invoking Throwable.printStackTrace() constitutes valid (not good/great) exception handling behavior, only

      • 如果您没有在应用程序的整个生命周期内重新分配 System.err
      • 如果您在应用程序运行时不需要日志轮换,
      • 如果接受/设计应用程序的日志记录做法是写入 System.err(以及 JVM 的标准错误输出流).
      • if you do not have System.err being reassigned throughout the duration of the application's lifetime,
      • and if you do not require log rotation while the application is running,
      • and if accepted/designed logging practice of the application is to write to System.err (and the JVM's standard error output stream).

      在大多数情况下,不满足上述条件.人们可能不知道在 JVM 中运行的其他代码,并且无法预测日志文件的大小或进程的运行时长,设计良好的日志记录实践将围绕编写机器可解析"日志文件(一种记录器中更可取但可选的功能)在已知目的地,以帮助支持.

      In most cases, the above conditions are not satisfied. One may not be aware of other code running in the JVM, and one cannot predict the size of the log file or the runtime duration of the process, and a well designed logging practice would revolve around writing "machine-parseable" log files (a preferable but optional feature in a logger) in a known destination, to aid in support.

      最后,应该记住 Throwable.printStackTrace() 的输出肯定会与写入 System.err(甚至可能是 System.out(如果两者都重定向到同一个文件/设备).这是一个必须处理的烦恼(对于单线程应用程序),因为在这种情况下,异常周围的数据不容易解析.更糟糕的是,多线程应用程序很可能会产生非常混乱的日志,因为 Throwable.printStackTrace() 不是线程安全的.

      Finally, one ought to remember that the output of Throwable.printStackTrace() would definitely get interleaved with other content written to System.err (and possibly even System.out if both are redirected to the same file/device). This is an annoyance (for single-threaded apps) that one must deal with, for the data around exceptions is not easily parseable in such an event. Worse, it is highly likely that a multi-threaded application will produce very confusing logs as Throwable.printStackTrace() is not thread-safe.

      当多个线程同时调用Throwable.printStackTrace() 时,没有同步机制将堆栈跟踪的写入同步到System.err.解决这个问题实际上需要您的代码在与 System.err(以及 System.out,如果目标文件/设备相同)关联的监视器上同步,并且为日志文件的完整性付出相当沉重的代价.举个例子,ConsoleHandlerStreamHandler 类负责将日志记录附加到控制台,在 java.util.logging;发布日志记录的实际操作是同步的——每个尝试发布日志记录的线程还必须获取与 StreamHandler 实例关联的监视器上的锁.如果您希望使用 System.out/System.err 获得非交错日志记录的相同保证,则必须确保相同 - 消息发布到这些以可序列化的方式流式传输.

      There is no synchronization mechanism to synchronize the writing of the stack trace to System.err when multiple threads invoke Throwable.printStackTrace() at the same time. Resolving this actually requires your code to synchronize on the monitor associated with System.err (and also System.out, if the destination file/device is the same), and that is rather heavy price to pay for log file sanity. To take an example, the ConsoleHandler and StreamHandler classes are responsible for appending log records to console, in the logging facility provided by java.util.logging; the actual operation of publishing log records is synchronized - every thread that attempts to publish a log record must also acquire the lock on the monitor associated with the StreamHandler instance. If you wish to have the same guarantee of having non-interleaved log records using System.out/System.err, you must ensure the same - the messages are published to these streams in a serializable manner.

      考虑到以上所有情况,以及 Throwable.printStackTrace() 实际上有用的非常有限的场景,事实证明调用它是一种不好的做法.

      Considering all of the above, and the very restricted scenarios in which Throwable.printStackTrace() is actually useful, it often turns out that invoking it is a bad practice.

      扩展前面一段中的论点,将 Throwable.printStackTrace 与写入控制台的记录器结合使用也是一个糟糕的选择.这部分是因为记录器会在不同的监视器上同步,而您的应用程序会(可能,如果您不想要交错的日志记录)在不同的监视器上同步.当您在应用程序中使用两个不同的记录器写入同一目的地时,这个论点也适用.

      Extending the argument in the one of the previous paragraphs, it is also a poor choice to use Throwable.printStackTrace in conjunction with a logger that writes to the console. This is in part, due to the reason that the logger would synchronize on a different monitor, while your application would (possibly, if you don't want interleaved log records) synchronize on a different monitor. The argument also holds good when you use two different loggers that write to the same destination, in your application.

      这篇关于为什么 exception.printStackTrace() 被认为是不好的做法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆