开发者

Drawback to catch-all exception (at highest program level, followed by re-raising, just to log before exiting?)

开发者 https://www.devze.com 2023-01-06 14:16 出处:网络
I have a long-running program on a remote machine and want to be sure that (1) I have a record of any exce开发者_运维百科ption that causes it to terminate and (2) someone is notified if it terminates.

I have a long-running program on a remote machine and want to be sure that (1) I have a record of any exce开发者_运维百科ption that causes it to terminate and (2) someone is notified if it terminates. Does anyone see drawbacks to the method I am using? (or have recommendations for a better one?)

I've read the Python docs and many exception-related posts here, and understand that blanket except clauses are usually a bad idea. Within subroutines and modules I always use except to handle specific expected exceptions, but it seems useful to have a "catch-all" except clause at the highest level of the program to ensure I can log the exception before the program exits.

What do you think?

import traceback
try:
    # main program code here
except BaseException:
    tb = traceback.format_exc()
    msg = "Exiting program due to exception:" + tb
    LogToFile(msg)         # custom logging function
    SendAlertEmail(msg)    # warn admin that program terminated
    raise                  # program exits with the existing exception

Note that I was using BaseException instead of Exception because if someone at the terminal presses Ctrl-C, I would like to log that as the reason for exiting the program (and alert an admin that the program was exited). But I suppose I could also use:

except Exception, KeyboardInterrupt:


There is no specific drawback, but there is an excellent alternative -- sys.excepthook.

In your specific version, consider using a bare except:, and sys.exc_info() to get the exception information; that will ensure you do catch everything -- even in the weird case where some module raises something else than an instance of a subclass of BaseException. E.g.:

>>> class X: pass
... 
>>> raise X
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
__main__.X: <__main__.X instance at 0xc9ad0>

As you see, it is still possible to raise something a except BaseException: would not catch -- that's why bare-except except: still exists (specifically for very special uses such as yours!).

Whether you use the hook, or build your own, consider (perhaps depending on configuration flags or environment settings) not burdening the end-user with all the details (just as a neat touch of improved user experience!), just a meaningful summary (reassuring the user that all details of the problem have been recorded, etc, etc).


Consider what happens if the exception is due to lack of diskspace. If the logging is written to the same partition

LogToFile(msg)

will raise an exception, an so no email is sent either. A simple try/except around each will avoid that problem

tb = traceback.format_exc()
msg = "Exiting program due to exception:" + tb
try:
    LogToFile(msg)         # custom logging function
except:
    pass
try:
    SendAlertEmail(msg)    # warn admin that program terminated
except:
    pass
raise                  # program exits with the existing exception


"I've read the Python docs and many exception-related posts here, and understand that blanket except clauses are usually a bad idea."

The rationale for that is that you might be expecting three kinds of exception then wind up swallowing the fourth kind that you never considered was a possibility. A handler that does an unconditional re-raise eliminates this concern -- you will be seeing unexpected exceptions -- so it's a perfectly cromulent exception to the general rule.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号