# 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)
import logging
try:
1/0
except ZeroDivisionError:
logging.exception("Deliberate divide by zero traceback")
使用默认(在最近版本中)记录仅将打印错误的行为记录到 sys.stderr ,它看起来像这样:
>>> 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
-6
如果使用普通日志 - 所有日志记录都应符合此规则: one record = one line . 遵循此规则,您可以使用 grep 和其他工具来处理日志文件 .
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('\n') for line in e_traceback]:
traceback_lines.extend(line.splitlines())
logger.log(level, traceback_lines.__str__())
之后(当您将分析日志时),您可以从日志文件中复制/粘贴所需的回溯行并执行以下操作:
ex_traceback = ['line 1', 'line 2', ...]
for line in ex_traceback:
print(line)
利润!
28
一个干净的方法是使用 format_exc() 然后解析输出以获取相关部分:
from traceback import format_exc
try:
1/0
except Exception:
print 'the relevant part is: '+format_exc().split('\n')[-2]
import traceback
def log_traceback(ex, ex_traceback=None):
if ex_traceback is None:
ex_traceback = ex.__traceback__
tb_lines = [ line.rstrip('\n') for line in
traceback.format_exception(ex.__class__, ex, ex_traceback)]
exception_logger.log(tb_lines)
在Python 2中使用它:
try:
# your function call is here
except Exception as ex:
_, _, ex_traceback = sys.exc_info()
log_traceback(ex, ex_traceback)
在Python 3中使用它:
try:
x = get_number()
except Exception as ex:
log_traceback(ex)
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
演示:
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'
9 回答
这个答案来自上述优秀的答案 .
在大多数应用程序中,您不会直接调用logging.exception(e) . 您很可能已经定义了一个特定于您的应用程序或模块的自定义 Logger ,如下所示:
在这种情况下,只需使用 Logger 来调用异常(e),如下所示:
关于
logging.exception
没有显示logging.exception
的一个好处是你可以传入任意消息,并且日志记录仍将显示包含所有异常详细信息的完整回溯:使用默认(在最近版本中)记录仅将打印错误的行为记录到
sys.stderr
,它看起来像这样:如果使用普通日志 - 所有日志记录都应符合此规则:
one record = one line
. 遵循此规则,您可以使用grep
和其他工具来处理日志文件 .但追溯信息是多线的 . 所以我的答案是在这个帖子中由zangw提出的解决方案的扩展版本 . 问题是回溯线内部可能有
\n
,所以我们需要做一些额外的工作来摆脱这一行的结局:之后(当您将分析日志时),您可以从日志文件中复制/粘贴所需的回溯行并执行以下操作:
利润!
一个干净的方法是使用
format_exc()
然后解析输出以获取相关部分:问候
Quoting
现在,
traceback
可以在这里使用 .一点点装饰处理(非常松散的启发可能monad和提升) . 您可以安全地删除Python 3.6类型注释并使用较旧的消息格式样式 .
fallible.py
演示:
你也可以修改这个解决方案,从
except
部分返回比None
更有意义的东西(或者甚至通过在fallible
的参数中指定这个返回值来使解决方案通用) .使用exc_info选项可能更好,允许您选择错误级别(如果使用
exception
,它将始终显示error
):如果你可以处理额外的依赖,那么使用twisted.log,你不必显式地记录错误,它也会返回整个回溯和文件或流的时间 .
logger.exception将在错误消息旁输出堆栈跟踪 .
例如:
输出:
@Paulo Cheque注意,“请注意,在Python 3中,您必须在
except
部分内部调用logging.exception
方法 . 如果您在任意位置调用此方法,您可能会遇到一个奇怪的异常 . 文档会提醒您 . ”