]> git.ipfire.org Git - pakfire.git/commitdiff
_pakfire: Setup a default logging callback
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 16 Oct 2023 10:35:27 +0000 (10:35 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 16 Oct 2023 10:35:27 +0000 (10:35 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/_pakfire/_pakfiremodule.c

index abdb210211f8c1e4f408257d268ae245160fcf74..1d93ed023078ba7cd61f00d617ce76142aa8e97d 100644 (file)
@@ -49,7 +49,103 @@ PyObject* PyExc_CheckFileVerificationError;
 
 struct pakfire_ctx* pakfire_ctx = NULL;
 
+static PyObject* setup_logger(void) {
+       PyObject* logging = NULL;
+       PyObject* logger = NULL;
+
+       // import logging
+       logging = PyImport_ImportModule("logging");
+       if (!logging)
+               goto ERROR;
+
+       // logging.getLogger("pakfire")
+       logger = PyObject_CallMethod(logging, "getLogger", "s", "pakfire");
+       if (!logger)
+               goto ERROR;
+
+ERROR:
+       Py_XDECREF(logging);
+
+       return logger;
+}
+
+static void __pakfire_log_callback(void* data, int level, const char* file, int line,
+               const char* fn, const char* format, va_list args) {
+       PyObject* logger = (PyObject*)data;
+       PyObject* result = NULL;
+       char* buffer = NULL;
+       int r;
+
+       PyObject* exception = NULL;
+       PyObject* type = NULL;
+       PyObject* value = NULL;
+       PyObject* traceback = NULL;
+
+       // Do nothing if the logger does not exist
+       if (!logger)
+               return;
+
+       // Translate priority to Python logging priorities
+       switch (level) {
+               case LOG_DEBUG:
+                       level = 10;
+                       break;
+
+               case LOG_INFO:
+                       level = 20;
+                       break;
+
+               case LOG_ERR:
+                       level = 40;
+                       break;
+
+               // Drop messages of an unknown level
+               default:
+                       return;
+       }
+
+       PyGILState_STATE state = PyGILState_Ensure();
+
+       // Format the log line
+       r = vasprintf(&buffer, format, args);
+       if (r < 0)
+               goto ERROR;
+
+       // Call the logger
+       result = PyObject_CallMethod(logger, "log", "is", level, buffer);
+       if (!result)
+               goto ERROR;
+
+ERROR:
+       /*
+               We cannot really catch any Python errors here, since we cannot send
+               any error codes up the chain.
+
+               So, in order to debug the problem, We will check if an exception has
+               occurred and if so, print it to the console.
+       */
+       exception = PyErr_Occurred();
+       if (exception) {
+               PyErr_Print();
+
+               // Fetch the exception and destroy it
+               PyErr_Fetch(&type, &value, &traceback);
+
+               Py_XDECREF(type);
+               Py_XDECREF(value);
+               Py_XDECREF(traceback);
+       }
+
+       if (buffer)
+               free(buffer);
+       Py_XDECREF(result);
+
+       // Release the GIL
+       PyGILState_Release(state);
+}
+
 static int initialize_context(void) {
+       PyObject* logger = NULL;
        int r;
 
        // Create a new context
@@ -59,12 +155,22 @@ static int initialize_context(void) {
                goto ERROR;
        }
 
+       // Setup the python logger
+       logger = setup_logger();
+       if (r)
+               goto ERROR;
+
+       // Pass all log messages to Python
+       pakfire_ctx_set_log_callback(pakfire_ctx, __pakfire_log_callback, logger);
+       Py_INCREF(logger);
+
        // Set the log level to DEBUG
        pakfire_ctx_set_log_level(pakfire_ctx, LOG_DEBUG);
 
 ERROR:
        if (pakfire_ctx)
                pakfire_ctx_unref(pakfire_ctx);
+       Py_XDECREF(logger);
 
        return r;
 }