管理 Python 扩展中的日志/警告
TL;DR 版本: 在 Python 项目的 C++ 位中,您使用什么来进行可配置(最好是捕获)日志记录?详细信息如下。
假设您有一些已编译的 .so
模块,它们可能需要进行一些错误检查并警告用户(部分)不正确的数据。目前,我的设置非常简单,使用来自 Python 代码的 logging
框架和来自 C/C++ 的 log4cxx
库。 log4cxx
日志级别在文件(log4cxx.properties
)中定义,目前已修复,我正在考虑如何使其更加灵活。我看到的几个选择:
控制它的一种方法是进行模块范围的配置调用。
<前><代码># foo/__init__.py 导入系统 从 _foo 导入导入 bar、baz、configure_log 配置日志(sys.stdout,警告) # 测试/test_foo.py def test_foo(): # 也许是一个自定义上下文来更改日志文件 # 模块并在最后恢复它。 以 CaptureLog(foo) 作为日志: 断言 foo.bar() == 5 断言 log.read() == "124.24 - foo - INFO - Bar 返回 5" 控制它的让每个进行日志记录的编译函数都接受可选的日志参数。
<前><代码># foo.c int bar(PyObject* x, PyObject* 日志文件, PyObject* 日志级别) { LoggerPtr 记录器 = default_logger("foo"); if (日志文件!= Py_None) logger = file_logger(日志文件,日志级别); ... } # 测试/test_foo.py def test_foo(): 使用 TemporaryFile() 作为日志文件: 断言 foo.bar(logfile=logfile, loglevel=DEBUG) == 5 断言 logfile.read() == "124.24 - foo - INFO - Bar 返回 5"还有其他方式吗?
第二个似乎更干净一些,但它需要函数签名更改(或使用 kwargs 并解析它们)。第一个是..可能有点尴尬,但是一次性设置了整个模块并从每个单独的函数中删除了逻辑。
您对此有何看法?我也热衷于替代解决方案。
谢谢,
TL;DR version: What do you use for configurable (and preferably captured) logging inside your C++ bits in a Python project? Details follow.
Say you have a a few compiled .so
modules that may need to do some error checking and warn user of (partially) incorrect data. Currently I'm having a pretty simplistic setup where I'm using logging
framework from Python code and log4cxx
library from C/C++. log4cxx
log level is defined in a file (log4cxx.properties
) and is currently fixed and I'm thinking how to make it more flexible. Couple of choices that I see:
One way to control it would be to have a module-wide configuration call.
# foo/__init__.py import sys from _foo import import bar, baz, configure_log configure_log(sys.stdout, WARNING) # tests/test_foo.py def test_foo(): # Maybe a custom context to change the logfile for # the module and restore it at the end. with CaptureLog(foo) as log: assert foo.bar() == 5 assert log.read() == "124.24 - foo - INFO - Bar returning 5"
Have every compiled function that does logging accept optional log parameters.
# foo.c int bar(PyObject* x, PyObject* logfile, PyObject* loglevel) { LoggerPtr logger = default_logger("foo"); if (logfile != Py_None) logger = file_logger(logfile, loglevel); ... } # tests/test_foo.py def test_foo(): with TemporaryFile() as logfile: assert foo.bar(logfile=logfile, loglevel=DEBUG) == 5 assert logfile.read() == "124.24 - foo - INFO - Bar returning 5"
Some other way?
Second one seems to be somewhat cleaner, but it requires function signature alteration (or using kwargs and parsing them). First one is.. probably somewhat awkward but sets up entire module in one go and removes logic from each individual function.
What are your thoughts on this? I'm all ears to alternative solutions as well.
Thanks,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我坚信在 Python 中进行尽可能多的工作,只将必须在 C 中进行的工作留在 C 中。所以我更喜欢 #2 而不是 #1,但你是对的,它会弄乱你所有的内容。函数签名。
我将创建一个模块级对象来处理日志记录,有点像回调。 Python 代码可以以任何喜欢的方式创建对象,然后将其分配给模块对象。 C 代码可以简单地使用全局对象来进行日志记录:
现在您可以在整个代码中简单地调用 C log_it 函数,而不必担心 Python 代码如何完成它。当然,您的 Python log_it 函数会比这个函数更丰富,它可以让您将所有日志记录集成到一个 Python 记录器中。
I'm a big believer in having as much work happen in Python as possible, leaving only the work that has to happen in C in C. So I like #2 better than #1, but you are right, it clutters up all your function signatures.
I'd create a module-level object to handle the logging, sort of like a callback. The Python code could create the object any way it likes, then assign it to the module object. The C code can simply use the global object to do its logging:
Now you can simply call the C log_it function throughout your code, and not worry about how the Python code gets it done. Of course, your Python log_it function would be richer than this one, and it would let you get all of your logging integrated into one Python logger.
谢谢你们提供的信息。我发现 PyObject_CallFunction 更容易使用。
Thanks for the information guys. I found the PyObject_CallFunction easier to use.