From 65e2817310e684a2e0a05ba127e949694331dc55 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Fri, 2 Aug 2019 13:43:59 -0400 Subject: [PATCH] bt2: move common internal functions to their own files This patch moves C code from `native_bt_component_class.i` to the new `native_bt_bt2_objects.h` and `native_bt_log_and_append_error.h` files, namely: * bt_bt2_init_from_bt2(), which was bt_bt2_cc_init_from_bt2() * bt_bt2_exit_handler(), which was bt_bt2_cc_exit_handler() * The common logging and error appending functions. This is just cleaner as those functions are not strictly related to the component class interface. Signed-off-by: Philippe Proulx Change-Id: Ic9d7fed993b94b45f624e28e4c512b5ccab776bd Reviewed-on: https://review.lttng.org/c/babeltrace/+/1814 Reviewed-by: Simon Marchi Tested-by: jenkins --- src/bindings/python/bt2/Makefile.am | 2 + src/bindings/python/bt2/bt2/__init__.py | 4 +- src/bindings/python/bt2/bt2/native_bt.i | 8 + .../python/bt2/bt2/native_bt_bt2_objects.h | 90 ++++++ .../bt2/bt2/native_bt_component_class.i | 2 - .../bt2/bt2/native_bt_component_class.i.h | 292 ------------------ .../bt2/bt2/native_bt_log_and_append_error.h | 251 +++++++++++++++ 7 files changed, 353 insertions(+), 296 deletions(-) create mode 100644 src/bindings/python/bt2/bt2/native_bt_bt2_objects.h create mode 100644 src/bindings/python/bt2/bt2/native_bt_log_and_append_error.h diff --git a/src/bindings/python/bt2/Makefile.am b/src/bindings/python/bt2/Makefile.am index 7c59af32..ce1058d8 100644 --- a/src/bindings/python/bt2/Makefile.am +++ b/src/bindings/python/bt2/Makefile.am @@ -7,6 +7,7 @@ INSTALLED_FILES=$(builddir)/installed_files.txt SWIG_INTERFACE_FILES = \ bt2/native_bt.i \ + bt2/native_bt_bt2_objects.h \ bt2/native_bt_clock_class.i \ bt2/native_bt_clock_snapshot.i \ bt2/native_bt_component.i \ @@ -23,6 +24,7 @@ SWIG_INTERFACE_FILES = \ bt2/native_bt_graph.i.h \ bt2/native_bt_integer_range_set.i \ bt2/native_bt_interrupter.i \ + bt2/native_bt_log_and_append_error.h \ bt2/native_bt_logging.i \ bt2/native_bt_message.i \ bt2/native_bt_message_iterator.i \ diff --git a/src/bindings/python/bt2/bt2/__init__.py b/src/bindings/python/bt2/bt2/__init__.py index 078ab0d0..d6e3ab2b 100644 --- a/src/bindings/python/bt2/bt2/__init__.py +++ b/src/bindings/python/bt2/bt2/__init__.py @@ -189,8 +189,8 @@ def _init_and_register_exit(): from bt2 import native_bt import atexit - atexit.register(native_bt.bt2_cc_exit_handler) - native_bt.bt2_cc_init_from_bt2() + atexit.register(native_bt.bt2_exit_handler) + native_bt.bt2_init_from_bt2() _init_and_register_exit() diff --git a/src/bindings/python/bt2/bt2/native_bt.i b/src/bindings/python/bt2/bt2/native_bt.i index 4f349f5c..6d9a3696 100644 --- a/src/bindings/python/bt2/bt2/native_bt.i +++ b/src/bindings/python/bt2/bt2/native_bt.i @@ -48,6 +48,10 @@ #include "common/assert.h" #include "py-common/py-common.h" + +/* Used by some interface files */ +#include "native_bt_bt2_objects.h" +#include "native_bt_log_and_append_error.h" %} typedef int bt_bool; @@ -182,6 +186,10 @@ typedef uint64_t bt_listener_id; $result = $1; } +/* Native part initialization and finalization */ +void bt_bt2_init_from_bt2(void); +void bt_bt2_exit_handler(void); + /* * Define `__BT_IN_BABELTRACE_H` to allow specific headers to be * included. This remains defined as long as we don't include the main diff --git a/src/bindings/python/bt2/bt2/native_bt_bt2_objects.h b/src/bindings/python/bt2/bt2/native_bt_bt2_objects.h new file mode 100644 index 00000000..dac2550c --- /dev/null +++ b/src/bindings/python/bt2/bt2/native_bt_bt2_objects.h @@ -0,0 +1,90 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "logging/comp-logging.h" + + +/* + * Useful Python objects. + */ + +static PyObject *py_mod_bt2 = NULL; +static PyObject *py_mod_bt2_exc_error_type = NULL; +static PyObject *py_mod_bt2_exc_memory_error = NULL; +static PyObject *py_mod_bt2_exc_try_again_type = NULL; +static PyObject *py_mod_bt2_exc_stop_type = NULL; +static PyObject *py_mod_bt2_exc_unknown_object_type = NULL; + +static +void bt_bt2_init_from_bt2(void) +{ + /* + * This is called once the bt2 package is loaded. + * + * Those modules and functions are needed while the package is + * used. Loading them here is safe because we know the bt2 + * package is imported, and we know that the user cannot use the + * code here without importing bt2 first. + */ + py_mod_bt2 = PyImport_ImportModule("bt2"); + BT_ASSERT(py_mod_bt2); + py_mod_bt2_exc_error_type = + PyObject_GetAttrString(py_mod_bt2, "_Error"); + BT_ASSERT(py_mod_bt2_exc_error_type); + py_mod_bt2_exc_memory_error = + PyObject_GetAttrString(py_mod_bt2, "_MemoryError"); + BT_ASSERT(py_mod_bt2_exc_memory_error); + py_mod_bt2_exc_try_again_type = + PyObject_GetAttrString(py_mod_bt2, "TryAgain"); + BT_ASSERT(py_mod_bt2_exc_try_again_type); + py_mod_bt2_exc_stop_type = + PyObject_GetAttrString(py_mod_bt2, "Stop"); + BT_ASSERT(py_mod_bt2_exc_stop_type); + py_mod_bt2_exc_unknown_object_type = + PyObject_GetAttrString(py_mod_bt2, "UnknownObject"); + BT_ASSERT(py_mod_bt2_exc_unknown_object_type); +} + +static +void bt_bt2_exit_handler(void) +{ + /* + * This is an exit handler (set by the bt2 package). + * + * We only give back the references that we took in + * bt_bt2_init_from_bt2() here. The global variables continue + * to exist for the code of this file, but they are now borrowed + * references. If this code is executed, it means that somehow + * the modules are still loaded, so it should be safe to use + * them even without a strong reference. + * + * We cannot do this in the library's destructor because it + * gets executed once Python is already finalized. + */ + Py_XDECREF(py_mod_bt2); + Py_XDECREF(py_mod_bt2_exc_error_type); + Py_XDECREF(py_mod_bt2_exc_try_again_type); + Py_XDECREF(py_mod_bt2_exc_stop_type); + Py_XDECREF(py_mod_bt2_exc_unknown_object_type); +} diff --git a/src/bindings/python/bt2/bt2/native_bt_component_class.i b/src/bindings/python/bt2/bt2/native_bt_component_class.i index ea8e9589..25f50df2 100644 --- a/src/bindings/python/bt2/bt2/native_bt_component_class.i +++ b/src/bindings/python/bt2/bt2/native_bt_component_class.i @@ -47,5 +47,3 @@ struct bt_component_class_filter *bt_bt2_component_class_filter_create( struct bt_component_class_sink *bt_bt2_component_class_sink_create( PyObject *py_cls, const char *name, const char *description, const char *help); -void bt_bt2_cc_init_from_bt2(void); -void bt_bt2_cc_exit_handler(void); diff --git a/src/bindings/python/bt2/bt2/native_bt_component_class.i.h b/src/bindings/python/bt2/bt2/native_bt_component_class.i.h index 6844fe1a..479f9abf 100644 --- a/src/bindings/python/bt2/bt2/native_bt_component_class.i.h +++ b/src/bindings/python/bt2/bt2/native_bt_component_class.i.h @@ -76,72 +76,6 @@ PyObject *lookup_cc_ptr_to_py_cls(const bt_component_class *bt_cc) (gconstpointer) bt_cc); } - -/* - * Useful Python objects. - */ - -static PyObject *py_mod_bt2 = NULL; -static PyObject *py_mod_bt2_exc_error_type = NULL; -static PyObject *py_mod_bt2_exc_memory_error = NULL; -static PyObject *py_mod_bt2_exc_try_again_type = NULL; -static PyObject *py_mod_bt2_exc_stop_type = NULL; -static PyObject *py_mod_bt2_exc_unknown_object_type = NULL; - -static -void bt_bt2_cc_init_from_bt2(void) -{ - /* - * This is called once the bt2 package is loaded. - * - * Those modules and functions are needed while the package is - * used. Loading them here is safe because we know the bt2 - * package is imported, and we know that the user cannot use the - * code here without importing bt2 first. - */ - py_mod_bt2 = PyImport_ImportModule("bt2"); - BT_ASSERT(py_mod_bt2); - py_mod_bt2_exc_error_type = - PyObject_GetAttrString(py_mod_bt2, "_Error"); - BT_ASSERT(py_mod_bt2_exc_error_type); - py_mod_bt2_exc_memory_error = - PyObject_GetAttrString(py_mod_bt2, "_MemoryError"); - BT_ASSERT(py_mod_bt2_exc_memory_error); - py_mod_bt2_exc_try_again_type = - PyObject_GetAttrString(py_mod_bt2, "TryAgain"); - BT_ASSERT(py_mod_bt2_exc_try_again_type); - py_mod_bt2_exc_stop_type = - PyObject_GetAttrString(py_mod_bt2, "Stop"); - BT_ASSERT(py_mod_bt2_exc_stop_type); - py_mod_bt2_exc_unknown_object_type = - PyObject_GetAttrString(py_mod_bt2, "UnknownObject"); - BT_ASSERT(py_mod_bt2_exc_unknown_object_type); -} - -static -void bt_bt2_cc_exit_handler(void) -{ - /* - * This is an exit handler (set by the bt2 package). - * - * We only give back the references that we took in - * bt_bt2_cc_init_from_bt2() here. The global variables continue - * to exist for the code of this file, but they are now borrowed - * references. If this code is executed, it means that somehow - * the modules are still loaded, so it should be safe to use - * them even without a strong reference. - * - * We cannot do this in the library's destructor because it - * gets executed once Python is already finalized. - */ - Py_XDECREF(py_mod_bt2); - Py_XDECREF(py_mod_bt2_exc_error_type); - Py_XDECREF(py_mod_bt2_exc_try_again_type); - Py_XDECREF(py_mod_bt2_exc_stop_type); - Py_XDECREF(py_mod_bt2_exc_unknown_object_type); -} - - /* Library destructor */ __attribute__((destructor)) @@ -154,232 +88,6 @@ void native_comp_class_dtor(void) { } } -static -void restore_current_thread_error_and_append_exception_chain_recursive( - int active_log_level, PyObject *py_exc_value, - bt_self_component_class *self_component_class, - bt_self_component *self_component, - bt_self_message_iterator *self_message_iterator, - const char *module_name) -{ - PyObject *py_exc_cause_value; - PyObject *py_exc_type = NULL; - PyObject *py_exc_tb = NULL; - GString *gstr = NULL; - - /* If this exception has a cause, handle that one first. */ - py_exc_cause_value = PyException_GetCause(py_exc_value); - if (py_exc_cause_value) { - restore_current_thread_error_and_append_exception_chain_recursive( - active_log_level, py_exc_cause_value, - self_component_class, self_component, - self_message_iterator, module_name); - } - - /* - * If the raised exception is a bt2._Error, restore the wrapped error. - */ - if (PyErr_GivenExceptionMatches(py_exc_value, py_mod_bt2_exc_error_type)) { - PyObject *py_error_swig_ptr; - const bt_error *error; - int ret; - - /* - * We never raise a bt2._Error with a cause: it should be the - * end of the chain. - */ - BT_ASSERT(!py_exc_cause_value); - - /* - * We steal the error object from the exception, to move - * it back as the current thread's error. - */ - py_error_swig_ptr = PyObject_GetAttrString(py_exc_value, "_ptr"); - BT_ASSERT(py_error_swig_ptr); - - ret = PyObject_SetAttrString(py_exc_value, "_ptr", Py_None); - BT_ASSERT(ret == 0); - - ret = SWIG_ConvertPtr(py_error_swig_ptr, (void **) &error, - SWIGTYPE_p_bt_error, 0); - BT_ASSERT(ret == 0); - - BT_CURRENT_THREAD_MOVE_ERROR_AND_RESET(error); - - Py_DECREF(py_error_swig_ptr); - } - - py_exc_type = PyObject_Type(py_exc_value); - py_exc_tb = PyException_GetTraceback(py_exc_value); - - gstr = bt_py_common_format_exception(py_exc_type, py_exc_value, - py_exc_tb, active_log_level, false); - if (!gstr) { - /* bt_py_common_format_exception has already warned. */ - goto end; - } - - if (self_component_class) { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT_CLASS( - self_component_class, "%s", gstr->str); - } else if (self_component) { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT( - self_component, "%s", gstr->str); - } else if (self_message_iterator) { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR( - self_message_iterator, "%s", gstr->str); - } else { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN( - module_name, "%s", gstr->str); - } - -end: - if (gstr) { - g_string_free(gstr, TRUE); - } - - Py_XDECREF(py_exc_cause_value); - Py_XDECREF(py_exc_type); - Py_XDECREF(py_exc_tb); -} - -/* - * If you have the following code: - * - * try: - * try: - * something_that_raises_bt2_error() - * except bt2._Error as e1: - * raise ValueError from e1 - * except ValueError as e2: - * raise TypeError from e2 - * - * We will have the following exception chain: - * - * TypeError -> ValueError -> bt2._Error - * - * Where the TypeError is the current exception (obtained from PyErr_Fetch). - * - * The bt2._Error contains a `struct bt_error *` that used to be the current - * thread's error, at the moment the exception was raised. - * - * This function gets to the bt2._Error and restores the wrapped - * `struct bt_error *` as the current thread's error. - * - * Then, for each exception in the chain, starting with the oldest one, it adds - * an error cause to the current thread's error. - */ -static -void restore_bt_error_and_append_current_exception_chain( - int active_log_level, - bt_self_component_class *self_component_class, - bt_self_component *self_component, - bt_self_message_iterator *self_message_iterator, - const char *module_name) -{ - BT_ASSERT(PyErr_Occurred()); - - /* Used to access and restore the current exception. */ - PyObject *py_exc_type; - PyObject *py_exc_value; - PyObject *py_exc_tb; - - /* Fetch and normalize the Python exception. */ - PyErr_Fetch(&py_exc_type, &py_exc_value, &py_exc_tb); - PyErr_NormalizeException(&py_exc_type, &py_exc_value, &py_exc_tb); - BT_ASSERT(py_exc_type); - BT_ASSERT(py_exc_value); - BT_ASSERT(py_exc_tb); - - /* - * Set the exception's traceback so it's possible to get it using - * PyException_GetTraceback in - * restore_current_thread_error_and_append_exception_chain_recursive. - */ - PyException_SetTraceback(py_exc_value, py_exc_tb); - - restore_current_thread_error_and_append_exception_chain_recursive( - active_log_level, py_exc_value, self_component_class, - self_component, self_message_iterator, module_name); - - PyErr_Restore(py_exc_type, py_exc_value, py_exc_tb); -} - -static inline -void log_exception_and_maybe_append_error(int func_log_level, - int active_log_level, bool append_error, - bt_self_component_class *self_component_class, - bt_self_component *self_component, - bt_self_message_iterator *self_message_iterator, - const char *module_name) -{ - GString *gstr; - - BT_ASSERT(PyErr_Occurred()); - gstr = bt_py_common_format_current_exception(active_log_level); - if (!gstr) { - /* bt_py_common_format_current_exception() logs errors */ - goto end; - } - - BT_COMP_LOG_CUR_LVL(func_log_level, active_log_level, self_component, - "%s", gstr->str); - - if (append_error) { - restore_bt_error_and_append_current_exception_chain( - active_log_level, self_component_class, self_component, - self_message_iterator, module_name); - - } - -end: - if (gstr) { - g_string_free(gstr, TRUE); - } -} - -static -bt_logging_level get_self_component_log_level(bt_self_component *self_comp) -{ - return bt_component_get_logging_level( - bt_self_component_as_component(self_comp)); -} - -static -bt_logging_level get_self_message_iterator_log_level( - bt_self_message_iterator *self_msg_iter) -{ - bt_self_component *self_comp = - bt_self_message_iterator_borrow_component(self_msg_iter); - - return get_self_component_log_level(self_comp); -} - -static inline -void loge_exception(const char *module_name, int active_log_level) -{ - log_exception_and_maybe_append_error(BT_LOG_ERROR, active_log_level, - true, NULL, NULL, NULL, module_name); -} - -static -void loge_exception_message_iterator( - bt_self_message_iterator *self_message_iterator) -{ - bt_logging_level log_level = get_self_message_iterator_log_level( - self_message_iterator); - - log_exception_and_maybe_append_error(BT_LOG_ERROR, log_level, - true, NULL, NULL, self_message_iterator, NULL); -} - -static inline -void logw_exception(int active_log_level) -{ - log_exception_and_maybe_append_error(BT_LOG_WARNING, active_log_level, - false, NULL, NULL, NULL, NULL); -} - static inline int py_exc_to_status(bt_self_component_class *self_component_class, bt_self_component *self_component, diff --git a/src/bindings/python/bt2/bt2/native_bt_log_and_append_error.h b/src/bindings/python/bt2/bt2/native_bt_log_and_append_error.h new file mode 100644 index 00000000..15295bbf --- /dev/null +++ b/src/bindings/python/bt2/bt2/native_bt_log_and_append_error.h @@ -0,0 +1,251 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "logging/comp-logging.h" + +static +void restore_current_thread_error_and_append_exception_chain_recursive( + int active_log_level, PyObject *py_exc_value, + bt_self_component_class *self_component_class, + bt_self_component *self_component, + bt_self_message_iterator *self_message_iterator, + const char *module_name) +{ + PyObject *py_exc_cause_value; + PyObject *py_exc_type = NULL; + PyObject *py_exc_tb = NULL; + GString *gstr = NULL; + + /* If this exception has a cause, handle that one first. */ + py_exc_cause_value = PyException_GetCause(py_exc_value); + if (py_exc_cause_value) { + restore_current_thread_error_and_append_exception_chain_recursive( + active_log_level, py_exc_cause_value, + self_component_class, self_component, + self_message_iterator, module_name); + } + + /* + * If the raised exception is a bt2._Error, restore the wrapped error. + */ + if (PyErr_GivenExceptionMatches(py_exc_value, py_mod_bt2_exc_error_type)) { + PyObject *py_error_swig_ptr; + const bt_error *error; + int ret; + + /* + * We never raise a bt2._Error with a cause: it should be the + * end of the chain. + */ + BT_ASSERT(!py_exc_cause_value); + + /* + * We steal the error object from the exception, to move + * it back as the current thread's error. + */ + py_error_swig_ptr = PyObject_GetAttrString(py_exc_value, "_ptr"); + BT_ASSERT(py_error_swig_ptr); + + ret = PyObject_SetAttrString(py_exc_value, "_ptr", Py_None); + BT_ASSERT(ret == 0); + + ret = SWIG_ConvertPtr(py_error_swig_ptr, (void **) &error, + SWIGTYPE_p_bt_error, 0); + BT_ASSERT(ret == 0); + + BT_CURRENT_THREAD_MOVE_ERROR_AND_RESET(error); + + Py_DECREF(py_error_swig_ptr); + } + + py_exc_type = PyObject_Type(py_exc_value); + py_exc_tb = PyException_GetTraceback(py_exc_value); + + gstr = bt_py_common_format_exception(py_exc_type, py_exc_value, + py_exc_tb, active_log_level, false); + if (!gstr) { + /* bt_py_common_format_exception has already warned. */ + goto end; + } + + if (self_component_class) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT_CLASS( + self_component_class, "%s", gstr->str); + } else if (self_component) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT( + self_component, "%s", gstr->str); + } else if (self_message_iterator) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR( + self_message_iterator, "%s", gstr->str); + } else { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN( + module_name, "%s", gstr->str); + } + +end: + if (gstr) { + g_string_free(gstr, TRUE); + } + + Py_XDECREF(py_exc_cause_value); + Py_XDECREF(py_exc_type); + Py_XDECREF(py_exc_tb); +} + +/* + * If you have the following code: + * + * try: + * try: + * something_that_raises_bt2_error() + * except bt2._Error as e1: + * raise ValueError from e1 + * except ValueError as e2: + * raise TypeError from e2 + * + * We will have the following exception chain: + * + * TypeError -> ValueError -> bt2._Error + * + * Where the TypeError is the current exception (obtained from PyErr_Fetch). + * + * The bt2._Error contains a `struct bt_error *` that used to be the current + * thread's error, at the moment the exception was raised. + * + * This function gets to the bt2._Error and restores the wrapped + * `struct bt_error *` as the current thread's error. + * + * Then, for each exception in the chain, starting with the oldest one, it adds + * an error cause to the current thread's error. + */ +static +void restore_bt_error_and_append_current_exception_chain( + int active_log_level, + bt_self_component_class *self_component_class, + bt_self_component *self_component, + bt_self_message_iterator *self_message_iterator, + const char *module_name) +{ + BT_ASSERT(PyErr_Occurred()); + + /* Used to access and restore the current exception. */ + PyObject *py_exc_type; + PyObject *py_exc_value; + PyObject *py_exc_tb; + + /* Fetch and normalize the Python exception. */ + PyErr_Fetch(&py_exc_type, &py_exc_value, &py_exc_tb); + PyErr_NormalizeException(&py_exc_type, &py_exc_value, &py_exc_tb); + BT_ASSERT(py_exc_type); + BT_ASSERT(py_exc_value); + BT_ASSERT(py_exc_tb); + + /* + * Set the exception's traceback so it's possible to get it using + * PyException_GetTraceback in + * restore_current_thread_error_and_append_exception_chain_recursive. + */ + PyException_SetTraceback(py_exc_value, py_exc_tb); + + restore_current_thread_error_and_append_exception_chain_recursive( + active_log_level, py_exc_value, self_component_class, + self_component, self_message_iterator, module_name); + + PyErr_Restore(py_exc_type, py_exc_value, py_exc_tb); +} + +static inline +void log_exception_and_maybe_append_error(int func_log_level, + int active_log_level, bool append_error, + bt_self_component_class *self_component_class, + bt_self_component *self_component, + bt_self_message_iterator *self_message_iterator, + const char *module_name) +{ + GString *gstr; + + BT_ASSERT(PyErr_Occurred()); + gstr = bt_py_common_format_current_exception(active_log_level); + if (!gstr) { + /* bt_py_common_format_current_exception() logs errors */ + goto end; + } + + BT_COMP_LOG_CUR_LVL(func_log_level, active_log_level, self_component, + "%s", gstr->str); + + if (append_error) { + restore_bt_error_and_append_current_exception_chain( + active_log_level, self_component_class, self_component, + self_message_iterator, module_name); + + } + +end: + if (gstr) { + g_string_free(gstr, TRUE); + } +} + +static +bt_logging_level get_self_component_log_level(bt_self_component *self_comp) +{ + return bt_component_get_logging_level( + bt_self_component_as_component(self_comp)); +} + +static +bt_logging_level get_self_message_iterator_log_level( + bt_self_message_iterator *self_msg_iter) +{ + bt_self_component *self_comp = + bt_self_message_iterator_borrow_component(self_msg_iter); + + return get_self_component_log_level(self_comp); +} + +static inline +void loge_exception(const char *module_name, int active_log_level) +{ + log_exception_and_maybe_append_error(BT_LOG_ERROR, active_log_level, + true, NULL, NULL, NULL, module_name); +} + +static +void loge_exception_message_iterator( + bt_self_message_iterator *self_message_iterator) +{ + bt_logging_level log_level = get_self_message_iterator_log_level( + self_message_iterator); + + log_exception_and_maybe_append_error(BT_LOG_ERROR, log_level, + true, NULL, NULL, self_message_iterator, NULL); +} + +static inline +void logw_exception(int active_log_level) +{ + log_exception_and_maybe_append_error(BT_LOG_WARNING, active_log_level, + false, NULL, NULL, NULL, NULL); +} -- 2.34.1