How do I log a Python error with debug information?
我正在用
1 2 3 4 5 | import logging try: 1/0 except ZeroDivisionError as e: logging.error(e) # ERROR:root:division by zero |
是否可以打印关于异常和生成异常的代码的更详细的信息,而不仅仅是异常字符串?像行号或堆栈跟踪之类的东西会很好。
例如:
1 2 3 4 5 | import logging try: 1/0 except ZeroDivisionError as e: logging.exception("message") |
输出:
1 2 3 4 | ERROR:root:message Traceback (most recent call last): File"<stdin>", line 2, in <module> ZeroDivisionError: integer division or modulo by zero |
@paulo check notes,"请注意,在python 3中,必须在
关于
1 2 3 4 5 | import logging try: 1/0 except ZeroDivisionError: logging.exception("Deliberate divide by zero traceback") |
由于默认(在最新版本中)只将错误打印到
1 2 3 4 5 6 7 8 9 10 | >>> import logging >>> try: ... 1/0 ... except ZeroDivisionError: ... logging.exception("Deliberate divide by zero traceback") ... ERROR:root:Deliberate divide by zero traceback Traceback (most recent call last): File"<stdin>", line 2, in <module> ZeroDivisionError: integer division or modulo by zero |
使用exc-info选项可能更好,以允许您选择错误级别(如果使用
1 2 3 4 | try: # do something here except Exception as e: logging.fatal(e, exc_info=True) # log exception info at FATAL log level |
引用
What if your application does logging some other way – not using the
logging module?
现在,可以在这里使用
1 2 3 4 5 6 7 8 9 | import traceback def log_traceback(ex, ex_traceback=None): if ex_traceback is None: ex_traceback = ex.__traceback__ tb_lines = [ line.rstrip(' ') for line in traceback.format_exception(ex.__class__, ex, ex_traceback)] exception_logger.log(tb_lines) |
在python 2中使用它:
1
2
3
4
5try:
# your function call is here
except Exception as ex:
_, _, ex_traceback = sys.exc_info()
log_traceback(ex, ex_traceback)在python 3中使用它:
1
2
3
4try:
x = get_number()
except Exception as ex:
log_traceback(ex)
如果您使用普通日志-您的所有日志记录都应符合以下规则:
但回溯信息是多行的。因此,我的答案是在本文中由Zangw提出的解决方案的扩展版本。问题是,回溯线内部可能有
1 2 3 4 5 6 7 8 9 10 11 12 | import logging logger = logging.getLogger('your_logger_here') def log_app_error(e: BaseException, level=logging.ERROR) -> None: e_traceback = traceback.format_exception(e.__class__, e, e.__traceback__) traceback_lines = [] for line in [line.rstrip(' ') for line in e_traceback]: traceback_lines.extend(line.splitlines()) logger.log(level, traceback_lines.__str__()) |
之后(在分析日志时),您可以从日志文件中复制/粘贴所需的回溯行,并执行以下操作:
1 2 3 | ex_traceback = ['line 1', 'line 2', ...] for line in ex_traceback: print(line) |
利润!
这个答案是由上述优秀的答案构成的。
在大多数应用程序中,您不会直接调用logging.exception(e)。很可能您已经为应用程序或模块定义了一个特定的自定义记录器,如下所示:
1 2 3 4 5 6 7 8 9 | # Set the name of the app or module my_logger = logging.getLogger('NEM Sequencer') # Set the log level my_logger.setLevel(logging.INFO) # Let's say we want to be fancy and log to a graylog2 log server graylog_handler = graypy.GELFHandler('some_server_ip', 12201) graylog_handler.setLevel(logging.INFO) my_logger.addHandler(graylog_handler) |
在这种情况下,只需使用记录器调用异常(e),如下所示:
1 2 3 4 | try: 1/0 except ZeroDivisionError, e: my_logger.exception(e) |
一点装饰处理(很松散的灵感可能是单子和起重)。您可以安全地删除python3.6类型注释并使用旧的消息格式样式。
错误的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | from functools import wraps from typing import Callable, TypeVar, Optional import logging A = TypeVar('A') def fallible(*exceptions, logger=None) \ -> Callable[[Callable[..., A]], Callable[..., Optional[A]]]: """ :param exceptions: a list of exceptions to catch :param logger: pass a custom logger; None means the default logger, False disables logging altogether. """ def fwrap(f: Callable[..., A]) -> Callable[..., Optional[A]]: @wraps(f) def wrapped(*args, **kwargs): try: return f(*args, **kwargs) except exceptions: message = f'called {f} with *args={args} and **kwargs={kwargs}' if logger: logger.exception(message) if logger is None: logging.exception(message) return None return wrapped return fwrap |
演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | In [1] from fallible import fallible In [2]: @fallible(ArithmeticError) ...: def div(a, b): ...: return a / b ...: ...: In [3]: div(1, 2) Out[3]: 0.5 In [4]: res = div(1, 0) ERROR:root:called <function div at 0x10d3c6ae8> with *args=(1, 0) and **kwargs={} Traceback (most recent call last): File"/Users/user/fallible.py", line 17, in wrapped return f(*args, **kwargs) File"<ipython-input-17-e056bd886b5c>", line 3, in div return a / b In [5]: repr(res) 'None' |
您还可以修改这个解决方案,从
如果您能够处理额外的依赖关系,那么就使用twisted.log,您不必显式地记录错误,它还会将整个回溯和时间返回到文件或流。
一种干净的方法是使用
1 2 3 4 5 6 7 | from traceback import format_exc try: 1/0 except Exception: print 'the relevant part is: '+format_exc().split(' ')[-2] |
当做