common/logging_backend: Introduce Python backend

pull/271/head
Olivier Martin 2024-02-22 00:17:09 +01:00 committed by Olivier Martin
parent 6751a17cee
commit 5f5cb5bd12
4 changed files with 83 additions and 2 deletions

View File

@ -61,7 +61,7 @@ endif()
# With 'syslog' backend, we enable all logs (ie: up to level debug) and we leave the
# application to set the level using 'setlogmask()'
set(GATTLIB_LOG_LEVEL 3 CACHE STRING "Define the minimum logging level for Gattlib (0=error, 1=warning, 2=info, 3=debug)")
set(GATTLIB_LOG_BACKEND syslog CACHE STRING "Define logging backend: syslog, printf (default: syslog)")
set(GATTLIB_LOG_BACKEND syslog CACHE STRING "Define logging backend: syslog, printf, python (default: syslog)")
if (GATTLIB_DBUS)
# Build dbus-based gattlib

View File

@ -0,0 +1,56 @@
/*
* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later
*
* Copyright (c) 2024, Olivier Martin <olivier@labapart.org>
*/
#include <syslog.h>
#include "gattlib_internal.h"
static PyObject* m_logging_func;
void gattlib_log_init(PyObject* logging_func) {
m_logging_func = logging_func;
}
void gattlib_log(int level, const char *format, ...) {
va_list args;
va_start(args, format);
if (m_logging_func == NULL) {
FILE *stream = stdout;
if (level == GATTLIB_ERROR) {
stream = stderr;
}
vfprintf(stream, format, args);
fprintf(stream, "\n");
} else {
PyGILState_STATE d_gstate;
PyObject *result;
char string[400];
vsnprintf(string, sizeof(string), format, args);
d_gstate = PyGILState_Ensure();
PyObject *arglist = Py_BuildValue("Is", level, string);
#if PYTHON_VERSION >= PYTHON_VERSIONS(3, 9)
result = PyObject_Call(m_logging_func, arglist, NULL);
#else
result = PyEval_CallObject(m_logging_func, arglist);
#endif
Py_DECREF(arglist);
if (result == NULL) {
GATTLIB_LOG(GATTLIB_ERROR, "Python notification handler has raised an exception.");
PyErr_Print();
}
PyGILState_Release(d_gstate);
}
va_end(args);
}

View File

@ -11,6 +11,28 @@ logger = logging.getLogger(__name__)
gattlib = CDLL("libgattlib.so")
def native_logging(level: int, string: str):
if level == 3:
logger.debug(string)
elif level == 2:
logger.info(string)
elif level == 1:
logger.warning(string)
elif level == 0:
logger.error(string)
else:
logger.debug(string)
try:
# void gattlib_log_init(PyObject* logging_func)
gattlib_log_init = gattlib.gattlib_log_init
gattlib_log_init.argtypes = [py_object]
# Declare Python function for logging native string
gattlib_log_init(native_logging)
except AttributeError:
# Excepted when using a Gattlib logging backend without 'gattlib_log_init'
pass
# typedef struct {
# uint8_t data[16];

View File

@ -78,7 +78,10 @@ class CMakeBuild(build_ext):
cmake_args += [item for item in os.environ["CMAKE_ARGS"].split(" ") if item]
# In this example, we pass in the version to C++. You might not need to.
cmake_args += [f"-DEXAMPLE_VERSION_INFO={self.distribution.get_version()}", "-DGATTLIB_BUILD_EXAMPLES=NO"]
cmake_args += [
f"-DEXAMPLE_VERSION_INFO={self.distribution.get_version()}",
"-DGATTLIB_BUILD_EXAMPLES=NO",
"-DGATTLIB_LOG_BACKEND=python"]
if self.compiler.compiler_type != "msvc":
# Using Ninja-build since it a) is available as a wheel and b)