Adding a function to sys.excepthook

Say I have something like this that sends unhanded exceptions to logging.critical() :

 import sys def register_handler(): orig_excepthook = sys.excepthook def error_catcher(*exc_info): import logging log = logging.getLogger(__name__) log.critical("Unhandled exception", exc_info=exc_info) orig_excepthook(*exc_info) sys.excepthook = error_catcher 

Works:

 import logging logging.basicConfig() register_handler() undefined() # logs, then runs original excepthook 

However, if register_handler() is called multiple times, several error_catcher is called in the chain, and the registration message appears several times.

I can come up with several methods, but none of them are particularly good (for example, if the sys.excepthook function is an error_catcher function or uses the has_registered attribute on a module to avoid double registration)

Is there a recommended way to do this?

+4
source share
4 answers

The presence at the module level of an โ€œalready registered hookโ€ variable seems to be the easiest and most reliable way to do this.

Other possible solutions will fall in certain (rather obscure) circumstances - if the sys.excepthook function is a built-in function, if the application registers a custom excepthook while maintaining the original excepthook during function definition, clobber subsequently registers the excepthook functions.

 import sys _hook_registered = False def register_handler(force = False): global _hook_registered if _hook_registered and not force: return orig_excepthook = sys.excepthook def error_catcher(*exc_info): import logging log = logging.getLogger(__name__) log.critical("Unhandled exception", exc_info=exc_info) orig_excepthook(*exc_info) sys.excepthook = error_catcher _hook_registered = True 
+1
source

You can simply check if there is still a sys.excepthook built-in function before registering the handler:

 >>> import sys, types >>> isinstance(sys.excepthook, types.BuiltinFunctionType) True >>> sys.excepthook = lambda x: x >>> isinstance(sys.excepthook, types.BuiltinFunctionType) False 
+3
source

If you put the code in your question into a module, you can import it many times, but it will only be executed for the first time.

+2
source

If you make an orig_excepthook argument with a default value, the default value is fixed once during the definition. Therefore, repeated calls to register_handler will not change orig_excepthook .

 import sys def register_handler(orig_excepthook=sys.excepthook): def error_catcher(*exc_info): import logging log = logging.getLogger(__name__) log.critical("Unhandled exception", exc_info=exc_info) orig_excepthook(*exc_info) sys.excepthook = error_catcher 

 import logging logging.basicConfig() register_handler() register_handler() register_handler() undefined() 

issues only one call to log.critical .

+1
source

Source: https://habr.com/ru/post/1385105/


All Articles