代码之家  ›  专栏  ›  技术社区  ›  Dimitri Tcaciuc

在Python扩展中管理日志/警告

  •  2
  • Dimitri Tcaciuc  · 技术社区  · 14 年前

    热释光;DR版本:

    假设你有一些 .so logging 来自Python代码和 log4cxx 来自C/C++的图书馆。 日志4CXX 日志级别在文件中定义( log4cxx.properties )现在已经修好了,我正在考虑如何使它更灵活。我看到了几个选择:

    1. # 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"
      
    2. 使每个已编译的日志函数都接受可选的日志参数。

      # 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"
      
    3. 还有别的办法吗?

    你对此有何看法?我也在全神贯注地寻找替代方案。

    2 回复  |  直到 14 年前
        1
  •  2
  •   Ned Batchelder    14 年前

    我非常相信在Python中有尽可能多的工作发生,只剩下C中必须发生的工作。所以我更喜欢#2而不是#1,但你是对的,它会把你所有的函数签名都弄乱。

    我将创建一个模块级对象来处理日志记录,有点像回调。Python代码可以按自己喜欢的方式创建对象,然后将其分配给module对象。C代码可以简单地使用全局对象进行日志记录:

    # Python:
    
    import my_compiled_module
    
    def log_it(level, msg):
        print "%s: Oh, look: %s" % (level, msg)
    
    my_compiled_module.logger = log_it
    
    # C
    
    static void log_it(unsigned int level, char * msg)
    {
        PyObject * args = Py_BuildValue("(Is)", level, msg);
        PyObject_Call(log_it, args, NULL);
        Py_DECREF(args);
    }
    

    现在,您只需在整个代码中调用C log\u it函数,而不用担心Python代码是如何完成的。当然,您的Python logit函数将比这个函数更丰富,它将允许您将所有日志集成到一个Python记录器中。

        2
  •  0
  •   Martlark    13 年前

    谢谢你们的消息。我发现PyObject\u call函数更容易使用。

    // C++ code with logger passed as 2nd argument
    static PyObject *lap_auction_assign(PyObject *self, PyObject *args)
    {
      PyObject *cost_dict;  PyObject *pyLogger;
     /* the O! parses for a Python object (listObj) checked to be of type PyList_Type */
      if( !PyArg_ParseTuple( args, "O!O", &PyDict_Type, &cost_dict, &pyLogger)) 
        return NULL;
    /*
    ....... then call the logger
    */
    
    char astring[2048];
    
    sprintf( astring, "%d out of %d rows un-assigned", no_new_list, num_rows );
    PyObject_CallFunction( pyLogger, "s", astring );
    
    /* python */
    # where logging is the python logging module and lap_auction is your extension
    cost_dict = {}
    tmp_assign_dict = lap_auction.assign( cost_dict, logging.info )