我在我的python程序中使用的软件包正在发出一个警告,表示我想了解其确切原因。我已设置logging.captureWarning(True)
并在我的日志记录中捕获警告,但仍不知道它来自何处。我如何记录堆栈跟踪,以便我可以看到警告来自哪里?我使用traceback
吗?
答案 0 :(得分:6)
虽然有点hackish,但你可以将warnings.warn
方法用于monkeypatch:
import traceback
import warnings
def g():
warnings.warn("foo", Warning)
def f():
g()
warnings.warn("bar", Warning)
_old_warn = warnings.warn
def warn(*args, **kwargs):
tb = traceback.extract_stack()
_old_warn(*args, **kwargs)
print("".join(traceback.format_list(tb)[:-1]))
warnings.warn = warn
f()
print("DONE")
这是输出:
/tmp/test.py:14: Warning: foo
_old_warn(*args, **kwargs)
File "/tmp/test.py", line 17, in <module>
f()
File "/tmp/test.py", line 8, in f
g()
File "/tmp/test.py", line 5, in g
warnings.warn("foo", Warning)
/tmp/test.py:14: Warning: bar
_old_warn(*args, **kwargs)
File "/tmp/test.py", line 17, in <module>
f()
File "/tmp/test.py", line 9, in f
warnings.warn("bar", Warning)
DONE
请注意,调用原始warnings.warn
函数不会报告您想要的行,但堆栈跟踪确实是正确的(您可以自己打印警告消息)。
答案 1 :(得分:4)
我最终选择了以下内容:
import warnings
import traceback
_formatwarning = warnings.formatwarning
def formatwarning_tb(*args, **kwargs):
s = _formatwarning(*args, **kwargs)
tb = traceback.format_stack()
s += ''.join(tb[:-1])
return s
warnings.formatwarning = formatwarning_tb
logging.captureWarnings(True)
答案 2 :(得分:1)
如果您不知道导致警告投掷的数据/指令,您可以使用标准Python Debugger等工具。
文档非常好且详细,但是一些可能有用的快速示例应该是:
不用修改源代码:调用debbugger作为脚本:
$ python -m pdb myscript.py
修改源代码:您可以使用对pdb.set_trace()
的调用,这些调用就像断点一样;例如,请考虑我有以下示例代码:
x = 2
x = x * 10 * 100
y = x + 3 + y
return y
我想知道 x 和 y 在返回之前有什么价值,或者堆栈包含什么,我会在这些语句之间添加以下行:
pdb.set_trace()
我将接受(Pdb)提示,这将允许您逐行浏览代码。 (Pdb)提示符的有用命令是:
由于您没有提供更多信息,我不知道这是否足够,但我认为至少,这可能是一个良好的开端。
BONUS EDIT
基于this answer,我发现有一个漂亮而友好的GUI调试工具,您可以通过以下方式安装:
$ pip 安装pudb
使用脚本运行调试器:
$ python -m pudb.run myscript.py
编辑:添加事后调试
如果我们甚至不知道代码是否会崩溃,我们可以在发生崩溃时输入 postmortem 调试。来自Pbd文档:
检查崩溃程序的典型用法是:
>>> import pdb >>> import mymodule >>> mymodule.test() Traceback (most recent call last): File "<stdin>", line 1, in ? File "./mymodule.py", line 4, in test test2() File "./mymodule.py", line 3, in test2 print spam NameError: spam >>> pdb.pm() > ./mymodule.py(3)test2() -> print spam (Pdb)
当 postmortem 查看sys.last_traceback
时,只有在有回溯时才会输入(等等,警告或崩溃):
if sys.last_traceback:
pdb.pm()
答案 3 :(得分:1)
您可以将警告变为异常,这意味着您将自动获得堆栈跟踪:
warnings.filterwarnings("error")
请参阅https://docs.python.org/3.4/library/warnings.html#the-warnings-filter
答案 4 :(得分:0)
如果是我,我会选择@LluísVilanova的快速&amp;肮脏的黑客,只是为了找到一些东西。但如果那不是一个选择......
如果你真的想要一个“日志记录”解决方案,你可以试试像this这样的东西(完全工作的来源)。
基本步骤是:
代码的核心是自定义格式化程序:
class Formatter(logging.Formatter):
def format(self, record):
record.stack_info = ''.join(traceback.format_stack())
return super().format(record)
根据docs:
New in version 3.2: The stack_info parameter was added.
答案 5 :(得分:0)
对于python 3.2及更高版本,使用可选的stack_info关键字参数是获取堆栈跟踪信息和日志消息的最简单方法。 在下面的示例中,“ Server.py”使用“ lib2.py”,而“ lib2.py”使用“ lib.py”。 启用stack_info参数后,完整的追溯记录将与每个logging.log()调用一起记录。这与logging.info()和其他便利方法相同。
用法:-
logging.log(DEBUG, "RWL [{}] : acquire_read()".format(self._ownerName), stack_info=True)
输出:-
2018-10-06 10:59:55,726|DEBUG|MainThread|lib.py|acquire_read|RWL [Cache] : acquire_read()
Stack (most recent call last):
File "./Server.py", line 41, in <module>
logging.info("Found {} requests for simulation".format(simdata.count()))
File "<Path>\lib2.py", line 199, in count
with basics.ReadRWLock(self.cacheLock):
File "<Path>\lib.py", line 89, in __enter__
self.rwLock.acquire_read()
File "<Path>\lib.py", line 34, in acquire_read
logging.log(DEBUG, "RWL [{}] : acquire_read()".format(self._ownerName), stack_info=True)