Verwalten von Protokollen / Warnungen in Python-Erweiterungen

TL, DR-Version: Was verwenden Sie für die konfigurierbare (und vorzugsweise erfasste) Protokollierung in Ihren C ++ – Bits in einem Python-Projekt? Details folgen.

Sagen Sie, Sie haben ein paar kompiliert. .so Module, die möglicherweise einige Fehler überprüfen und warnen Benutzer von (teilweise) falsche Daten zu tun haben. Derzeit bin ich mit einem ziemlich simplen Setup, wo ich mit logging Framework aus Python-Code und log4cxx Bibliothek aus C / C ++. log4cxx Log-Ebene ist in einer Datei ( log4cxx.properties ) definiert und ist derzeit behoben und ich denke, wie man es flexibler macht. Paar von Entscheidungen, die ich sehe:

  1. Eine Möglichkeit, es zu kontrollieren, wäre ein modularweiter Konfigurationsaufruf.

     # 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. Haben Sie jede kompilierte Funktion, die Protokollierung akzeptieren optionale Log-Parameter.

     # 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. Irgendwie anders

Zweitens scheint etwas sauberer zu sein, aber es erfordert Funktionsunterschrift Änderung (oder mit Kwargs und analysiert sie). Erster ist wahrscheinlich etwas unangenehm, aber setzt das gesamte Modul in einem Zug und entfernt Logik aus jeder einzelnen Funktion.

Was sind deine Gedanken dazu? Ich bin alle Ohren auch für alternative Lösungen.

Vielen Dank,

2 Solutions collect form web for “Verwalten von Protokollen / Warnungen in Python-Erweiterungen”

Ich bin ein großer Gläubiger, so viel Arbeit in Python wie möglich zu machen, so dass nur die Arbeit, die in C in C passieren muss. Also ich mag # 2 besser als # 1, aber du hast recht, es klammert alle deine Funktionssignaturen.

Ich würde ein Modul-Level-Objekt erstellen, um die Protokollierung zu behandeln, Art wie ein Callback. Der Python-Code könnte das Objekt beliebig erstellen und dann dem Modulobjekt zuordnen. Der C-Code kann einfach das globale Objekt verwenden, um seine Protokollierung durchzuführen:

 # 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); } 

Jetzt kannst du einfach die C log_it Funktion während deines Codes anrufen und dich nicht darum kümmern, wie der Python Code es macht. Natürlich wäre deine Python-Log_it-Funktion reicher als diese, und es würde dir alles von deinem Logging in einen Python-Logger integrieren lassen.

Danke für die Information Jungs. Ich fand die PyObject_CallFunction einfacher zu bedienen.

 // 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 ) 
  • Testen eines Python-API-Clients
  • Erhalten der End-Speicher-Adresse eines Speicherbereichs über Python / Ctypes
  • Tkinter's event_generate Befehl ignoriert
  • Einheit testet ganze Projekthierarchie in Python mit unittest in pydev
  • Wie gruppiere ich Unit-Tests in Django bei einer höheren Granularität als die App?
  • Spott eine Steckdose in Python
  • Wie behaupte ich, dass ein Funktionsaufruf keinen Fehler mit unittest zurückgibt?
  • Nase nicht laufen Django Dokthen
  • Wiederholungscode in unbescheidenem Testfall
  • Verwenden von unittest.mock zum Patch-Eingabe () in Python 3
  • Wie kann ich einen Redis-Client in Python verspotten?
  • Python ist die beste Programmiersprache der Welt.