2

TL;DR バージョン: Python プロジェクトの C++ ビット内の構成可能な (そしてできればキャプチャされた) ログに何を使用しますか? 詳細は次のとおりです。

.soエラーチェックを実行し、(部分的に) 不正確なデータをユーザーに警告する必要があるコンパイル済みモジュールがいくつかあるとします。logging現在、Python コードのフレームワークとlog4cxxC/C++ のライブラリを使用する、かなり単純なセットアップを行っています。log4cxxログ レベルはファイル ( log4cxx.properties) で定義されており、現在は修正されており、より柔軟にする方法を考えています。私が見るいくつかの選択肢:

  1. それを制御する 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番目のものはややきれいに見えますが、関数シグネチャの変更(またはkwargsを使用してそれらを解析する)が必要です。最初のものは..おそらくやや厄介ですが、モジュール全体を一度にセットアップし、個々の関数からロジックを削除します。

これについてどう思いますか?私はすべて、代替ソリューションにも耳を傾けています。

ありがとう、

4

2 に答える 2

2

私はできるだけ多くの作業を Python で行い、C で行わなければならない作業だけを C で行うことを強く信じています。だから私は #1 よりも #2 の方が好きですが、その通りです。関数シグネチャ。

コールバックのようなもので、ロギングを処理するモジュール レベルのオブジェクトを作成します。Python コードは、好きな方法でオブジェクトを作成し、それをモジュール オブジェクトに割り当てることができます。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_it 関数を呼び出すことができ、Python コードがそれをどのように実行するかを気にする必要がなくなりました。もちろん、Python の log_it 関数はこれよりも機能が豊富で、すべてのログを 1 つの Python ロガーに統合できます。

于 2010-06-08T11:49:29.613 に答える
0

情報ありがとうございます。PyObject_CallFunction の方が使いやすいことがわかりました。

// 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 )
于 2011-11-11T00:31:38.930 に答える