113

This question was sparked by a discussion around this article, where I did not receive any good answers.

Why should logging your exception and then rethrowing it (preserving the original stack trace of course) be a bad idea if you can't handle it otherwise?

Community
  • 1
  • 1
Manu
  • 28,753
  • 28
  • 75
  • 83
  • Try searching for an answer on https://softwareengineering.stackexchange.com/ – chharvey May 08 '18 at 03:22
  • @chharvey: Maybe this one? [Try/Catch/Log/Rethrow - Is Anti Pattern?](https://softwareengineering.stackexchange.com/questions/365427/try-catch-log-rethrow-is-anti-pattern) – sleske Jan 04 '23 at 08:41

4 Answers4

163

I assume the answer is largely because why are you catching it if you can't handle it? Why not let whomever can handle it (or whomever is left with no choice but to handle it) log it, if they feel that it is log-worthy?

If you catch it and log it and rethrow it, then there's no way for the upstream code to know that you've already logged the exception, and so the same exception might get logged twice. Or worse, if all the upstream code follows this same pattern, the exception might be logged an arbitrary number of times, once for each level in the code that decides to catch it, log it, and then throw it again.

Also some might argue that since throwing and catching exceptions are relatively costly operations, all this catching and rethrowing isn't helping your runtime performance. Nor is it helping your code in terms of conciseness or maintainability.

aroth
  • 54,026
  • 20
  • 135
  • 176
  • for further elaboration, see the comments on Jeff's answer – Manu Jul 10 '11 at 08:36
  • 14
    A reason for logging-and-rethrowing an exdeption whould be to narrow down the reason and log a specific message. – Mike Argyriou Sep 26 '14 at 12:15
  • 25
    Answer : there might useful debug information available at the current point in the stack that will not be available at another point in the stack trace – rtconner Jul 25 '17 at 00:55
  • 1
    Catching and rethrowing is sometimes helpful if the new exception is more helpful with more information or more specific. – borjab Oct 19 '17 at 11:06
  • 1
    To expend on what @rtconner commented: in async code it might be that the catcher doesn't have the context which is available to the thrower. – Nir Alfasi Feb 25 '20 at 19:37
  • 3
    Isn't this why you can usually attach information to an exception before you re-throw them again or wrap them into another exception? – S. Mense Jul 21 '20 at 08:22
80

Log-and-throw is a good pattern iff the entity catching and rethrowing the exception has reason to believe that it contains information which will not get logged further up the call stack--at least not in the most-desired fashion. A couple of reasons this may occur:

  1. The exception may be caught and rethrown at an application-layer boundary, and may contain privileged information. It would be bad for a database layer to allow an exception saying, e.g. "Attempt to add duplicate key 'fnord' to field 'users'" to reach the outer application layer (which might in turn expose it to a user), but it could be useful for inner portions of the database to throw such an exception and the application interface to catch it, log it securely, and rethrow a somewhat less descriptive exception.
  2. The exception may be one that the outer layer would likely be expecting to handle without logging, but the inner layer may know something that the outer layer doesn't which would suggest that logging may be useful. As a crude example, a middle application layer might be programmed to try connecting to one server and, if that doesn't work, try another. Flooding the application's log with 'connection failed' messages while a server is down for maintenance might not be helpful, especially since--from the application's perspective, everything worked fine. It may be useful to forward information about the connection failure to a logging resource associated with servers, which could then filter the logs so as to produce a report of when the server went up and down, as opposed to a log of every single connection attempt.
If an outer layer would cause information from an exception to get lost, having an inner layer log and rethrow the exception may help ensure that it gets retained.
supercat
  • 77,689
  • 9
  • 166
  • 211
  • 4
    #1 is indeed a sensible general use case, however the OP explicitly asked about "rethrowing it (preserving the original stack trace of course)", so #1 is not the right answer. – Geoffrey Zheng May 07 '15 at 02:45
  • @GeoffreyZheng: That would depend upon whether logging the original stack trace securely would count as "preserving". – supercat May 07 '15 at 13:15
  • 5
    Regarding #1: exposing exception content (like displaying `e.getMessage()`/stacktrace on UI, as well as sending it as REST response) should be treated as vulnerability itself, as runtime exception may contain any kind of sensitive information. Regarding #2: you can re-throw exception adding all information you want client to know (+root cause), no need to log anything. – Nikita Bosik Jun 28 '18 at 17:57
  • @NikitaBosik: Whether or not exceptions should be exposed client-side, applications that do so are sufficiently common that the 'security in depth' principle would suggest that exception messages should be scrubbed of sensitive information. Further, if the outer layer isn't expecting to discard a particular type of an exception without logging it nor forwarding information to an outside entity that might be interested, having a middle layer add information the outer layer is going to ignore won't help anything. – supercat Jun 28 '18 at 18:37
  • I cannot see how #2 is an example of the log-and-throw as suggested. #2 is described as not logging the exception (instead forward) and not throwing it either (since another server was used). So it's not an example for a log-and-throw. What am I missing? – GrumpyRodriguez Jun 23 '22 at 12:24
  • @GrumpyRodriguez: My point was that #1 and #2 are things that an *outer* layer might do that would make it useful for an *inner* layer to use log-and-throw. – supercat Jun 23 '22 at 12:38
  • 1
    @GrumpyRodriguez: Do you like the last paragraph? – supercat Jun 24 '22 at 14:47
  • 1
    @supercat yes, that helps clarify your point. Thanks for putting the extra effort into this answer after 10+ years! – GrumpyRodriguez Jun 24 '22 at 15:46
29

I guess the simplest reason is that you'd typically have a single top-level handler doing this for you, so there's no need to pollute the code with this exception handling.

The cross-cutting concerns argument is basically that it is a waste of time handling errors that don't concern you. Far better to let the error bubble up the call stack until an appropriate handler can be found.

In my opinion, the only time you should catch an exception is when you can do something useful with the results. Catching simply to log is not useful, because you could centralize that work further up.

Jeff Foster
  • 43,770
  • 11
  • 86
  • 103
  • 2
    I agree that you should have a single top-level handler doing this for you. But in my opinion, that top level handler SHOULD be "log and throw"-ing. So the argument is around AT WHICH POINT to "log and throw", not wether or not to do it at all?!? – Manu Jul 10 '11 at 08:23
  • @Manu, I guess the point is that if it is a single handler (centralized), that's fine. If you are duplicating code, that's not fine. I don't think there's any more to it than that! – Jeff Foster Jul 10 '11 at 08:24
  • 8
    @Manu - What is the top-level handler throwing to in that case? It seems to me that if there is something available for it to throw to, then it is not really the top-level handler. And you definitely don't want to be rethrowing an exception up to the runtime environment itself. That will bring most applications to a crashing halt. – aroth Jul 10 '11 at 08:28
  • 1
    @aroth: I see, what you are saying is either "log and handle" (if you are the top-level handler) or "don't log and throw (or handle otherwise)" if you are not. Thanks for pointing that out. – Manu Jul 10 '11 at 08:32
14

IMO log and throw is a clear violation of the Principle of Least Surprise.

If the exception is handled properly further up the call stack, it might not be worth an error log entry at all. And then it is confusing to find an error log entry.

Bastian Voigt
  • 5,311
  • 6
  • 47
  • 65