I created a CustomExceptionClass that its messages are from a configuration file and are a friendlier message to the user.
Then I want to log wich exception was thrown because, if something went wrong, I want to know details then I can fix this. So, I have a doubt.
Where to log these exceptions using log4j? Inside the CustomExceptionClass, or I let the method that throws this exception log it?
You should log wherever you are catching the Exception. If you are not catching it anywhere it really depends how you are running your application.
I'm not sure if you have a question about log4j in particular, but that API simply requires something to call log.error(Object,Throwable), passing in the message as the first parameter and the error as the second parameter. (log is of course a Log4J logger reference.)
Regarding the question of where to call log.error, do not call log.error from within your CustomExceptionClass subclass of Throwable. Instead, I'd make the decision as follows:
If you want to log details about exactly what happened, but you don't plan to put those details into your subclass of Exception, then log the details before throwing the error.
Similarly, if you want to log something specific regardless of whether or how the Exception is caught, then obviously you need to do this before throwing the Exception. You have relatively little control over who calls a non-private method.
Otherwise log in the catch block. This allows you to track both what happened and how your application responded as a result. If you just have the first piece of information, then other people will have to read the code in order to understand "so what?"
Finally, it's considered to be good practice to use uncaught exception handlers for all threads. See Thread.UncaughtExceptionHandler for more details. Basically you really want to at least log all Exceptions in long-running applications.
You should log it in the error handling code, not where the error is initially created.
I typically overload ToString and/or GetMessage in custom exceptions and simply log them per normal.
Related
Is the following way to code good practice?
try {
//my code here
} catch (Exception e) {
logger.error("Some error ", e);
throw new MyCustomException("Some error ", e);
}
Moreover, should I..
use only the logger?
throw only the exception?
do both?
I understand that with throw I can catch the exception in another part of the callstack, but maybe additional logging has some hidden benefits and is useful as well.
Normally, I'd argue that you should either log or rethrow. Doing both will just cause every layer to log the exception again and again, which makes the logs hard to read. Even worse, it's hard to figure out how many errors you actually have - was it seven errors, or seven layers of the app which logged the same error?
This means that if you suppress an exception, you log it and say why you didn't think it was worth rethrowing.
On the other hand, if you re-throw the exception, you know it's either going to be caught and suppressed (in which case the catcher logs the exception and why it was suppressed), or it will bubble up out of your app and be caught by the app container, which will catch and log the exception. Every exception shows up once and only once in the logs.
I use both in some cases, logging and throwing the exception. Especially, it's useful in APIs. By throwing the exception, we allow the caller to handle it, and by logging, we can identify the root cause of it ourselves.
And, if the caller is in the same system, then if we add logs in every catch, there will be duplicate logs.
When using the pattern you suggest, you usually end up with error events being reported multiple times in the log. In addition, it's not always simple to connect between them when reading the log.
Personally I prefer logging error events only once, and doing it in the higher call levels. Therefore I almost never log & re-throw. I usually let the exception go up the call stack until it reached a context where it can be handled somehow, and this is where I log.
If the exceptions are wrapped and re-thrown correctly, the context should be perfectly clear from the stack traces of the single log message.
The proper answer would be: "it depends"
You do want in general log the exceptions that you catch, since they correspond to something going wrong. That is why code analysis tools such as sonar will raise warnings when you do not log them.
Consider the following taks: parsing a file. While parsing the file you actually try to parse each line. Sometimes some lines will be malformed, and therefore you don't want to stop parsing the file because of it. In that case, you probably want to just log the wrong line and keep going on the file.
However, imagine that at some point you encounter an I/O exception while reading (for example some other program deleted the file while yours was accessing it).
In this case, you will probably want to log your log the error you encounter, and throw a new exception to stop processing the whole file.
So in short, you have to think about what is the best thing to do. But both practices are not bad.
I think you may need to use the pattern judiciously. As you've written the above, for each exception you're going to log 2 stacktraces and that may fill your logs with excessive information.
With respect to logging vs. throwing, they're two separate concerns. Throwing an exception will interrupt your execution, prevent any further work, perhaps rollback database commits etc. Logging will simply dump info to the log file (or elsewhere). It's of more use for debugging, and often much more difficult to test.
I know that is really old question, but I have an another solution.
Consider this. You can log the problem in catch block and throw a new unchecked exception (of course with passing the previous one inside). In such solution there is no overflow in the logs and exception still bubble up to the highest level.
try {
//my code here
} catch (SomeException e) {
logger.error("Some error occured", e);
throw new MyUncheckedException("Some error ", e);
}
My opinion.
When you need to throw an exception, no matter if it is a Checked or UnChecked(Most RD would not catch this.). It means that you want to do something else by stopping the process.
When you need to log something.
It means you want to track it.
It's quite different things.
You need to check what you really need.
BTW: If your exception was thrown by getting no data from DB.
I suggest you to modify the process to return an empty Data Object(POJO). It is better than throwing an exception.
I have a generic question regarding to how to design error handling. I want to use some third-party service in my code. Normally I wrap the service within a client class. Then the rest of my code only deals with my client class and is blind to the real service under the hook. My client class has some mechanism to log errors. But it doesn't want to catch and deal any exception from the service. Ideally it should just ignore the exception handling and let the exception propagates to outside. However, if I want to log the exception, I have to do something like this:
try{
.... // call 3rd party service;
}catch(Exception e){ // e is triggered from the service;
Log.error("Oops, an error: " + e); // shall I log the exception??
throw e; // don't swallow the exception;
}
On one hand, I don't want to do this. I can ignore the handling and logging of the exception. Let the caller of my client class handles exceptions or logs errors. The question is, when should I log exceptions and when should I not? I'd like to hear some common practice and principles. Thank you.
Don't log the exception at every level. Log it only at the "top" level. Log it at the point where not logging it would cause the exception to be missed.
That depends on you. My recommendations are to log the exceptions when they indicate something truly unexpected. Granted, the name "exception" would seem to indicate that this is always the case, but not necessarily.
Sometimes, code returns exceptions for scenarios that are unexeceptional.
Sometimes, code calls other code, knowing it will invoke exceptions in certain cases, but the set of exceptions is "OK".
Sometimes, an exception indicates something unexpected really did happen, and that's usually a bad thing. That's when you should log it, or better yet, make sure your code complains loudly.
If there is a fairly low chance of triggering the exception, I see no real reason not to log it. The only reason to not log an exception to help with debugging is if it is continually firing. If you have an exception that has this characteristic, then I suggest you write your code so that you don't have exceptions continually being triggered.
tl;dr: Exceptions are (hopefully) rare, so log them.
I've got a decently complex little game going on in Java (solitaire, essentially like the Windows version), but I have yet to do very much error handling.
Almost all of the methods across my classes will end up either getting called by an initial constructor (eventually main()), a paintComponent() method, or a mouse event. So, my question is, is it bad practice to just use "throws Exception" on all of my lower-level methods, and only do a try/catch at my top-level methods to catch ALL the errors at once? (e.g. 3 try/catches - one for the painting, one for mouse events, one for the main method).
I realize this prevents me from easily dealing with errors on-the-spot, but I don't really plan on doing that anyways. My error handling is going to consist of writing to a log, telling the user, and killing the program. Keeping this in mind, is there anything bad with doing my error handling this way?
It depends on how you want to approach the situation.
If you just want to catch any possible exception and you don't mind about the handler code, you could simply use "throws exception", and there's nothing BAD with it either. It's like a try-catch block that covers all the function.
If you want to write specific code for specific exceptions, you should use try-catch blocks to write appropriate code for each handler.
Based on what you're saying, any caught exception would just notify the user and exit the application. Well, in this case you could just use the first approach. It's not necessarily the BEST approach, and neither is killing the application, however, if that's your strategy you could just use "throws" for each function.
Hope that helps!
If that's all you wan't to do in a case of an error, then it makes perfect sense to do it that way. This eliminates code duplication and scattering of related code. However, if you're thinking of changing how things work in the future (if there's a possibility of this happening), I would suggest to try and push the catch down as far as possible (maybe even eliminating the need for exceptions at all and just logging and exiting right away).
If you use the exception's inner fields (specifically message, which you can set in construction time), you can even eliminate the need for 3 different catch blocks and just use one (depending on your actual actions in case of an error, of course).
I wouldn't - the big reason being that it breaks encapsulation. The reason why this is important in this case is that your error handling code has one of two futures:
Becoming enormous to handle in an informative way every error the program can throw.
Be tiny but not helpful at all: "Some error occurred somewhere".
To my mind, the best structure is to catch the error, log it, alert the user, and exit as far down as possible. There's nothing that says your mouse handling code can't exit, right?
In fact, I would create an error handler class that you can call from just about anywhere, and it handles the notification and logging. Then your exception handlers can just populate it with the message to display/log, and all other code is shared. It will cost you less typing to delegate to this class than adding throws Exception at the end of every function everywhere.
If you must have a top level handler, it should just catch any unexpected runtime errors, so that you can log it and show the user that the program is really quitting for an error, and not just dump to the desktop. All other errors - even if you just want to bail out - should be caught as close to "where the exception has meaning" as possible.
I do the same thing as you are describing most of the time. What you're basically doing is working around the stupid checked exceptions that Java has. It shouldn't even be necessary to add 'throws Exception' everywhere.
If I'm working on an API that other users will use I may create specific exceptions to show what is going on in case they want to handle different exceptions in different ways.
If an error is severe enough to always exit the program, you may be better of throwing a RuntimeException instead. They are used to indicate unrecoverable errors and will avoid problems with putting "throws Exception" everywhere. You should have a handler for RuntimeExceptions anyway to provide a user-friendly error report in case they happen.
If you throw checked exceptions, they should be as specific as possible. Throwing and catching Exception can hide other exceptions that are thrown (including RuntimeExceptions) that you didn't intend and could have been handled differently. If you want to throw a general exception, you can always create your own exception class and throw that instead.
The exception handling can depend on the context so there's not one way to handle everything. If the user clicks a button to open a file and there's an error reading it, then it would be ok to throw an IOException up to the UI layer and display an error message there. On the other hand, an IOException while creating a temporary file could be handled lower down by retrying in another directory.
I'm trying to better understand exception handling and logging in a j2ee environment to refactor some legacy code (we use log4j for our logging mechanism). Most of our current code does something like the code below on the business tier, however, I'd like to switch over to unchecked exceptions and just ignore them unless it makes sense to handle them somewhere:
try {
doSomething();
} catch (MyException e) {
log.error("Exception:", e);
throw e;
}
After the exception is thrown in the business tier, it is then propagated up to the presentation tier, which again catches the exception and usually wraps it in a PortletException or ServletException and throws it again. Then, it is handled by a Spring handler which shows a 'friendly' message to the user. I'd ultimately like to only handle exceptions for which we want to show a specific error message, and just ignore everything else.
Questions:
Is it necessary to log exceptions in the business tier? If not, do
I need to log exceptions at all (especially unchecked ones)?
What happens to uncaught exceptions that are not logged using log4j?
(If they're still printed in the console, what's the purpose of
log4j?)
I am confused as to how the process works...
Thanks.
EDIT: If an exception occurs in an outside library (Spring, Hibernate, etc), is it assumed that these exceptions will be printed out using whatever logging mechanism is being used? In that case, I guess that I would only need to log the exceptions that my code throws... or am I way off base here?
Before proceeding any further, please take a careful look at:
The following are some of the generally accepted principles of
exception handling:
If you can't handle an exception, don't catch it.
If you catch an exception, don't swallow it.
Catch an exception as close as possible to its source.
Log an exception where you catch it, unless you plan to rethrow it.
Structure your methods according to how fine-grained your exception handling must be.
Use as many typed exceptions as you need, particularly for application exceptions.
Point 1 is obviously in conflict with Point 3. The practical solution is a trade-off >?between how close to the source you catch an exception and how far you let it fall before you've completely lost the intent or content of the original exception.
IBM DeveloperWorks: EJB best practices
It is usually advised that you use checked exceptions for application exceptions at the business tier. I prefer to follow the business interface pattern to decouple the business tier from the user interface and web tier. This will allow me to think of your business tier as a service layer library and callers might want to handle different situations differently when calling this layer. That is one reason you might want to include checked exceptions, since you can react differently to different exceptions. Furthermore, including checked exceptions will usually help the caller code to be better aware of what different situations might arise from invoking some functionality. It could be worth it to take a look at the business delegate pattern and how it might help you with exception handling. In short, the business delegate pattern allows you to create a very thin layer between the business layer and the web layer where you can do things like exception handling.
No matter how you go about doing this, make sure that you understand the implication of adding an application exception to your Java EE application. You may need to investigate how it interacts with your transaction management logic, specifically when it comes to transaction rollbacks. In my line of work, I had to add an #ApplicationException(rollback=false) to forbid the transaction manager from rolling back my transaction when an exception is thrown and propagated upwards.
You may be able to tell I was working with EJB, but the concepts are probably very applicable to your design as well.
So back to your questions:
Is it necessary to log exceptions in the business tier?
It is not necessary if you plan to log it later on. You better devise a logging strategy at a high level and log all caught exceptions there.
If not, do I need to log exceptions at all (especially unchecked
ones)?
I think that you should log exceptions because that will help you debug any issues later on. The user is usually not savvy enough to capture any output that might be produced if the exception propagates and gets printed on his/her screen without you handling it.
What happens to uncaught exceptions that are not logged using log4j?
(If they're still printed in the console, what's the purpose of
log4j?)
I think it will eventually be caught by the web container and be printed out to the console. If an exception propagates upwards and reaches the web container exception handling safety nets, your exception is out of control. It is usually a sign of bad design. It is best if you keep your exceptions under control. Why wonder how a container will react to an uncaught exception? Also how beneficial will that exception be to the user? I think the information presented from uncaught exceptions are almost useless, as they are so far from the source of the error, that they become irrelevant and hard to work with when debugging.
You could create your own exception hierarchy to wrap them to quickly identify from where in your application architecture it is originating. Also one can go a step further to provide codes and reasons that covers majoority of the use cases.
What logging helps you is to identify the sequence of events, when potentially multiple clients are slamming the same use case or hitting a bottle neck. The logging give you a sequence to trace back because requests increasesed there was congestion in this query causing it to timeout and thus other users where seeing another exception.
While handling the application and showing it to the user is another issue.
Cheers!
We definitely do not have to handle exceptions just to log them. I believe we should catch exception if we then throw other exception that contains the source exception as its cause or if we implement some logic that must be implemented in current layer when exception is thrown.
Yes, it is a little bit verbose to declare all methods as throws MyException. This is the reason that Spring (that you use) prefer working with unchecked exceptions. BTW this is the new feature in Java 7: you can ignore exceptions without declaring that method throws it.
I believe that we still need checked exceptions for development of libraries that expose API to 3rd party applications. Application layer exceptions should be mostly runtime and be caught in one central place.
Is it necessary to log exceptions in the business tier?
No. But more logs = better understanding what is going on. In other way more logs = lower performance.
What happens to uncaught exceptions that are not logged using log4j?
You lost them. Logger pretty things that you can save logs in the place where you need and use filters to get only actual logs for now.
You don't need to catch the business exception (as long as it's unchecked). You don't need to handle them or to log them. You can just swallow them. The problem is - what is such exception for?
Exception signals some inappropriate behaviour in the workflow of your application. If it's checked you, typically, can do something about it - try do some operation again, do some workaround, try different action, etc.
If it's unchecked, it is typically an exception you don't know how or can't handle.
It's considered a code smell if all you do is catch an exception and log it. It's not as bad as swallowing it, but still - it's not good.
Some of the containers (i.e. EJB) is required to log occurred exceptions. Moreover, in EJB 3.x if you're in a JTA managed transaction, and you won't catch an unchecked exception which is not marked as #ApplicationException(rollback=false) than the transaction will be automatically rolled back. This might be the reason why you can see some try...catch blocks with just logging code inside.
If you want to get rid of exception handling code in your business logic, you might introduce an interceptor which will react appropriately upon particular exceptions.
HTH!
Firstly, you can and must log the exception stack trace of all exceptions. In fact, IMO if you only log that an exception happened you might as well not log it at all. However, very often what this leads to is a relaxed view of exceptions. What you should strive for is to have 2 log files or one specific category that if exceptions are in that category they mean something critical happened and must be addressed. Even if that means logging the same exception many times. Rather too many than not at all.
Secondly, it's fine to change all exceptions to checked exceptions - the majority of exceptions are not "recoverable". What I have done that worked well is simply wrap all transactions in an exception handling wrapper which logged the exception, then I can guarantee that all exceptions are logged. Furthermore, create a bunch of exception classes that extend runtime exception - this is much better than rethrowing exceptions as runtime exceptions as very often the inner exception stack trace is not logged in full when you wrap exceptions.
And thirdly, it is important to create a mechanism to map exceptions that do filter through to the front end with the back end cause. This is challenging but it's quite important. Errors that the user sees are far easy to track down if you can map them back to an exception stack trace in the log file.
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?
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
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.
Inferring from the above, invoking Throwable.printStackTrace() constitutes valid (not good/great) exception handling behavior, only
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).
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 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.
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.
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.
You are touching multiple issues here:
1) A stack trace should never be visibile to end users (for user experience and security purposes)
Yes, it should be accessible to diagnose problems of end-users, but end-user should not see them for two reasons:
They are very obscure and unreadable, the application will look very user-unfriendly.
Showing a stack trace to end-user might introduce a potential security risk. Correct me if I'm wrong, PHP actually prints function parameters in stack trace - brilliant, but very dangerous - if you would you get exception while connecting to the database, what are you likely to in the stacktrace?
2) Generating a stack trace is a relatively expensive process (though unlikely to be an issue in most 'exception'al circumstances)
Generating a stack trace happens when the exception is being created/thrown (that's why throwing an exception comes with a price), printing is not that expensive. In fact you can override Throwable#fillInStackTrace() in your custom exception effectively making throwing an exception almost as cheap as a simple GOTO statement.
3) Many logging frameworks will print the stack trace for you (ours does not and no, we can't change it easily)
Very good point. The main issue here is: if the framework logs the exception for you, do nothing (but make sure it does!) If you want to log the exception yourself, use logging framework like Logback or Log4J, to not put them on the raw console because it is very hard to control it.
With logging framework you can easily redirect stack traces to file, console or even send them to a specified e-mail address. With hardcoded printStackTrace() you have to live with the sysout.
4) Printing the stack trace does not constitute error handling. It should be combined with other information logging and exception handling.
Again: log SQLException correctly (with the full stack trace, using logging framework) and show nice: "Sorry, we are currently not able to process your request" message. Do you really think the user is interested in the reasons? Have you seen StackOverflow error screen? It's very humorous, but does not reveal any details. However it ensures the user that the problem will be investigated.
But he will call you immediately and you need to be able to diagnose the problem. So you need both: proper exception logging and user-friendly messages.
To wrap things up: always log exceptions (preferably using logging framework), but do not expose them to the end-user. Think carefully and about error-messages in your GUI, show stack traces only in development mode.
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);
Printing the exception's stack trace in itself doesn't constitute bad practice, but only printing the stace trace when an exception occurs is probably the issue here -- often times, just printing a stack trace is not enough.
Also, there's a tendency to suspect that proper exception handling is not being performed if all that is being performed in a catch block is a e.printStackTrace. Improper handling could mean at best an problem is being ignored, and at worst a program that continues executing in an undefined or unexpected state.
Example
Let's consider the following example:
try {
initializeState();
} catch (TheSkyIsFallingEndOfTheWorldException e) {
e.printStackTrace();
}
continueProcessingAssumingThatTheStateIsCorrect();
Here, we want to do some initialization processing before we continue on to some processing that requires that the initialization had taken place.
In the above code, the exception should have been caught and properly handled to prevent the program from proceeding to the continueProcessingAssumingThatTheStateIsCorrect method which we could assume would cause problems.
In many instances, e.printStackTrace() is an indication that some exception is being swallowed and processing is allowed to proceed as if no problem every occurred.
Why has this become a problem?
Probably one of the biggest reason that poor exception handling has become more prevalent is due to how IDEs such as Eclipse will auto-generate code that will perform a e.printStackTrace for the exception handling:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
(The above is an actual try-catch auto-generated by Eclipse to handle an InterruptedException thrown by Thread.sleep.)
For most applications, just printing the stack trace to standard error is probably not going to be sufficient. Improper exception handling could in many instances lead to an application running in a state that is unexpected and could be leading to unexpected and undefined behavior.
I think your list of reasons is a pretty comprehensive one.
One particularly bad example that I've encountered more than once goes like this:
try {
// do stuff
} catch (Exception e) {
e.printStackTrace(); // and swallow the exception
}
The problem with the above code is that the handling consists entirely of the printStackTrace call: the exception isn't really handled properly nor is it allowed to escape.
On the other hand, as a rule I always log the stack trace whenever there's an unexpected exception in my code. Over the years this policy has saved me a lot of debugging time.
Finally, on a lighter note, God's Perfect Exception.
printStackTrace() prints to a console. In production settings, nobody is ever watching at that. Suraj is correct, should pass this information to a logger.
It is not bad practice because something is 'wrong' about PrintStackTrace(), but because it's 'code smell'.
Most of the time the PrintStackTrace() call is there because somebody failed to properly handle the exception. Once you deal with the exception in a proper way you generally don't care about the StackTrace any more.
Additionally, displaying the stacktrace on stderr is generally only useful when debugging, not in production because very often stderr goes nowhere. Logging it makes more sense. But just replacing PrintStackTrace() with logging the exception still leaves you with an application which failed but keeps running like nothing happened.
In server applications the stacktrace blows up your stdout/stderr file. It may become larger and larger and is filled with useless data because usually you have no context and no timestamp and so on.
e.g. catalina.out when using tomcat as container
As some guys already mentioned here the problem is with the exception swallowing in case you just call e.printStackTrace() in the catch block. It won't stop the thread execution and will continue after the try block as in normal condition.
Instead of that you need either try to recover from the exception (in case it is recoverable), or to throw RuntimeException, or to bubble the exception to the caller in order to avoid silent crashes (for example, due to improper logger configuration).