Python logging.critical() 引发异常并转储堆栈跟踪和死亡



我正在从perl(log4perl(和java(slf4j(移植一些代码。一切都很好,除了logging.critical((不会像在其他框架中那样转储堆栈跟踪和死亡,需要添加大量额外的代码,logger.exception((也只写入错误。

今天我做:

try:
    errmsg = "--id={} not found on --host={}".format(args.siteid, args.host)
    raise GX8Exception(errmsg)
except GX8Exception as e:
    log.exception(e)
    sys.exit(-1)

这会产生:

2018-01-10 10:09:56,814 [ERROR   ] root         --id=7A4A7845-7559-4F89-B678-8ADFECF5F7C3 not found on --host=welfare-qa
Traceback (most recent call last):
  File "./gx8-controller.py", line 85, in <module>
    raise GX8Exception(errmsg)
GX8Exception: --id=7A4A7845-7559-4F89-B678-8ADFECF5F7C3 not found on --host=welfare-qa

有没有办法配置 pythonmodule 记录器来执行此操作,或任何其他框架来执行此操作:

log.critical("--id={} not found on --host={}".format(args.siteid, args.host))

一种方法是创建一个自定义处理程序,该处理程序除了将日志消息传递到其超级处理器外什么都不做,然后在日志级别足够高时退出:

import logging
class ExitOnExceptionHandler(logging.StreamHandler):
    def emit(self, record):
        super().emit(record)
        if record.levelno in (logging.ERROR, logging.CRITICAL):
            raise SystemExit(-1)

logging.basicConfig(handlers=[ExitOnExceptionHandler()], level=logging.DEBUG)
logger = logging.getLogger('MYTHING')
def causeAProblem():
    try:
        raise ValueError("Oh no!")
    except Exception as e:
        logger.exception(e)
logger.warning('Going to try something risky...')
causeAProblem()
print("This won't get printed")

输出:

rat@pandion:~$ python test.py
ERROR:root:Oh no!
Traceback (most recent call last):
  File "test.py", line 14, in causeAProblem
    raise ValueError("Oh no!")
ValueError: Oh no!
rat@pandion:~$ echo $?
255

但是,这可能会导致代码用户出现意外行为。如果要记录异常并退出,只需不捕获异常即可,这将更加直接。如果要记录回溯并退出代码当前调用logging.critical的任何位置,请将其更改为引发异常。

我继承了一些无法更改处理程序类的代码。我求助于处理程序的运行时修补,这是 @nathan-vērzemnieks 对解决方案的变体:


import types
def patch_logging_handler(logger):
    def custom_emit(self, record):
        self.orig_emit(record)
        if record.levelno == logging.FATAL:
            raise SystemExit(-1)
    handler = logger.handlers[0]
    setattr(handler, 'orig_emit', handler.emit)
    setattr(handler, 'emit', types.MethodType(custom_emit, handler))

Nathans anwser很棒!寻找这个很久了,
只会补充一点,你也可以做:

if record.levelno >= logging.ERROR:

而不是

if record.levelno in (logging.ERROR, logging.CRITICAL):

以设置会导致退出的最低级别。

最新更新