There is a lot of material out there which suggests that printing the stack trace of an exception is bad practice.
E.g. from the RegexpSingleline check in Checkstyle:
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:
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?
printStackTrace()
prints to a console. In production settings, nobody is ever watching at that. Suraj is correct, should pass this information to a logger.Throwable.printStackTrace()
writes the stack trace toSystem.err
PrintStream. TheSystem.err
stream and the underlying standard "error" output stream of the JVM process can be redirected bySystem.setErr()
which changes the destination pointed to bySystem.err
./dev/null
.Inferring from the above, invoking
Throwable.printStackTrace()
constitutes valid (not good/great) exception handling behavior, onlySystem.err
being reassigned throughout the duration of the application's lifetime,System.err
(and the JVM's standard error output stream).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.
Finally, one ought to remember that the output of
Throwable.printStackTrace()
would definitely get interleaved with other content written toSystem.err
(and possibly evenSystem.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 asThrowable.printStackTrace()
is not thread-safe.There is no synchronization mechanism to synchronize the writing of the stack trace to
System.err
when multiple threads invokeThrowable.printStackTrace()
at the same time. Resolving this actually requires your code to synchronize on the monitor associated withSystem.err
(and alsoSystem.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, theConsoleHandler
andStreamHandler
classes are responsible for appending log records to console, in the logging facility provided byjava.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 theStreamHandler
instance. If you wish to have the same guarantee of having non-interleaved log records usingSystem.out
/System.err
, you must ensure the same - the messages are published to these streams in a serializable manner.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.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.First thing printStackTrace() is not expensive as you state, because the stack trace is filled when the exception is created itself.
The idea is to pass anything that goes to logs through a logger framework, so that the logging can be controlled. Hence instead of using printStackTrace, just use something like
Logger.log(msg, exception);