kuuko pushed a commit to branch master. http://git.enlightenment.org/bindings/python/python-efl.git/commit/?id=7fbab02702bb1318a7519fd80833ad0856c33812
commit 7fbab02702bb1318a7519fd80833ad0856c33812 Author: Kai Huuhko <kai.huu...@gmail.com> Date: Wed Oct 23 14:34:42 2013 +0300 First attempt at integrating Eina Log with Python logging. Has two loggers: efl and efl.eo. To test, add handlers, formatters etc. and change levels using normal Python logging utilities. The test messages come from efl.eo init and class registration. --- efl/eo/efl.eo.pyx | 98 ++++++++++++++++++++++++++++++++++++++++++---------- include/efl.c_eo.pxd | 2 +- include/efl.eina.pxd | 50 +++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 19 deletions(-) diff --git a/efl/eo/efl.eo.pyx b/efl/eo/efl.eo.pyx index 31a6bfe..451d8ce 100644 --- a/efl/eo/efl.eo.pyx +++ b/efl/eo/efl.eo.pyx @@ -15,28 +15,84 @@ # You should have received a copy of the GNU Lesser General Public License # along with this Python-EFL. If not, see <http://www.gnu.org/licenses/>. -from cpython cimport PyObject, Py_INCREF, Py_DECREF, PyUnicode_AsUTF8String +cimport cython +from cpython cimport PyObject, Py_INCREF, Py_DECREF, PyUnicode_AsUTF8String, \ + PyString_FromFormatV from libc.stdlib cimport malloc, free from libc.string cimport memcpy, strdup from efl.eina cimport Eina_Bool, const_Eina_List, eina_list_append, const_void, \ Eina_Hash, eina_hash_string_superfast_new, eina_hash_add, eina_hash_del, \ - eina_hash_find + eina_hash_find, Eina_Log_Domain, const_Eina_Log_Domain, Eina_Log_Level, \ + eina_log_print_cb_set, eina_log_domain_register, \ + eina_log_level_set, eina_log_level_get, eina_log_domain_level_get, \ + eina_log_domain_level_set, EINA_LOG_DOM_DBG, EINA_LOG_DOM_INFO from efl.c_eo cimport Eo as cEo, eo_init, eo_shutdown, eo_del, eo_do, \ eo_class_name_get, eo_class_get, eo_base_data_set, eo_base_data_get, \ eo_base_data_del, eo_event_callback_add, eo_event_callback_del, \ Eo_Event_Description, const_Eo_Event_Description, \ eo_parent_get, EO_EV_DEL -###################################################################### -# -# TODO: Automate these -# -# Call eo_init and put eo_shutdown to atexit, and don't expose in our API. -# -# Do the same in other packages as well, making sure the packages main -# module is always imported. -# + +cdef extern from "stdarg.h": + ctypedef struct va_list: + pass + +cdef void py_eina_log_print_cb(const_Eina_Log_Domain *d, + Eina_Log_Level level, + const_char *file, const_char *fnc, int line, + const_char *fmt, void *data, va_list args) with gil: + + cdef str msg = PyString_FromFormatV(fmt, args) + rec = logging.LogRecord(d.name, log_levels[level], file, line, msg, None, None, fnc) + loggers[d.name].handle(rec) + +eina_log_print_cb_set(py_eina_log_print_cb, NULL) + + +import logging + +cdef tuple log_levels = ( + 50, + 40, + 30, + 20, + 10 +) + +cdef dict loggers = dict() + +class PyEFLLogger(logging.Logger): + def __init__(self, name): + self.eina_log_domain = eina_log_domain_register(name, NULL) + loggers[name] = self + logging.Logger.__init__(self, name) + + def setLevel(self, lvl): + eina_log_domain_level_set(self.name, log_levels.index(lvl)) + logging.Logger.setLevel(self, lvl) + +logging.setLoggerClass(PyEFLLogger) + +# TODO: Handle messages from root Eina Log with this one? +rootlog = logging.getLogger("efl") +rootlog.propagate = False +rootlog.setLevel(logging.WARNING) +rootlog.addHandler(logging.NullHandler()) + +log = logging.getLogger(__name__) +log.propagate = True +log.setLevel(logging.WARNING) +log.addHandler(logging.NullHandler()) + +logging.setLoggerClass(logging.Logger) + +cdef int PY_EFL_EO_LOG_DOMAIN = log.eina_log_domain + + + + def init(): + EINA_LOG_DOM_INFO(PY_EFL_EO_LOG_DOMAIN, "Initializing %s", <char *>__name__) return eo_init() def shutdown(): @@ -50,14 +106,15 @@ cdef int PY_REFCOUNT(object o): return obj.ob_refcnt - ###################################################################### - """ + Object mapping is an Eina Hash table into which object type names can be registered. These can be used to find a bindings class for an object using -the object_from_instance function.""" +the function object_from_instance. + +""" cdef Eina_Hash *object_mapping = eina_hash_string_superfast_new(NULL) @@ -66,7 +123,7 @@ cdef void _object_mapping_register(char *name, object cls) except *: if eina_hash_find(object_mapping, name) != NULL: raise ValueError("Object type name '%s' already registered." % name) - #print("REGISTER: %s => %s" % (name, cls)) + EINA_LOG_DOM_DBG(PY_EFL_EO_LOG_DOMAIN, "REGISTER: %s => %s", name, <char *>cls.__name__) eina_hash_add(object_mapping, name, <PyObject *>cls) @@ -115,10 +172,13 @@ cdef object object_from_instance(cEo *obj): cdef void _register_decorated_callbacks(object obj): - """ Serach every attrib of the pyobj for a __decorated_callbacks__ object, + """ + + Search every attrib of the pyobj for a __decorated_callbacks__ object, a list actually. If found then exec the functions listed there, with their arguments. Must be called just after the _set_obj call. List items signature: ("function_name", *args) + """ cdef object attr_name, attrib, func_name, func @@ -159,8 +219,10 @@ cdef Eina_Bool _eo_event_del_cb(void *data, cEo *obj, const_Eo_Event_Description cdef class Eo(object): """ + Base class used by all the Eo object in the bindings, its not meant to be used by users, but only by internal classes. + """ # c globals declared in eo.pxd (to make the class available to others) @@ -175,13 +237,13 @@ cdef class Eo(object): def __str__(self): return ("Eo(class=%s, obj=%#x, parent=%#x, refcount=%d)") % \ (type(self).__name__, <unsigned long>self.obj, - <unsigned long>eo_parent_get(self.obj) if self.obj != NULL else 0, + <unsigned long><void *>eo_parent_get(&self.obj) if self.obj != NULL else 0, PY_REFCOUNT(self)) def __repr__(self): return ("Eo(class=%s, obj=%#x, parent=%#x, refcount=%d)") % \ (type(self).__name__, <unsigned long>self.obj, - <unsigned long>eo_parent_get(self.obj) if self.obj != NULL else 0, + <unsigned long><void *>eo_parent_get(&self.obj) if self.obj != NULL else 0, PY_REFCOUNT(self)) def __nonzero__(self): diff --git a/include/efl.c_eo.pxd b/include/efl.c_eo.pxd index e313bcd..62696e1 100644 --- a/include/efl.c_eo.pxd +++ b/include/efl.c_eo.pxd @@ -72,7 +72,7 @@ cdef extern from "Eo.h": const_Eo_Class *eo_class_get(const_Eo *obj) const_char *eo_class_name_get(const_Eo_Class *klass) - Eo *eo_parent_get(const_Eo *obj) + Eo *eo_parent_get(Eo **obj) void eo_event_callback_add(const_Eo_Event_Description *desc, Eo_Event_Cb cb, const_void *data) void eo_event_callback_del(const_Eo_Event_Description *desc, Eo_Event_Cb cb, const_void *data) diff --git a/include/efl.eina.pxd b/include/efl.eina.pxd index 1da12ce..9e11dde 100644 --- a/include/efl.eina.pxd +++ b/include/efl.eina.pxd @@ -15,6 +15,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with this Python-EFL. If not, see <http://www.gnu.org/licenses/>. +from cpython cimport va_list from libc.stdlib cimport const_void, malloc, free from libc.string cimport const_char, memcpy, strdup @@ -38,6 +39,18 @@ cdef extern from "Eina.h": #################################################################### # Enumerations # + ctypedef enum Eina_Log_Level: + EINA_LOG_LEVEL_CRITICAL # Critical log level + EINA_LOG_LEVEL_ERR # Error log level + EINA_LOG_LEVEL_WARN # Warning log level + EINA_LOG_LEVEL_INFO # Information log level + EINA_LOG_LEVEL_DBG # Debug log level + EINA_LOG_LEVELS # Count of default log levels + EINA_LOG_LEVEL_UNKNOWN = (-2147483647 - 1) # Unknown level + + ctypedef enum Eina_Log_State: + EINA_LOG_STATE_START + EINA_LOG_STATE_STOP #################################################################### # Basic Types @@ -78,11 +91,22 @@ cdef extern from "Eina.h": void *(*get_container)(Eina_Iterator *it) void (*free)(Eina_Iterator *it) + ctypedef struct Eina_Log_Domain: + int level # Max level to log + const char *domain_str # Formatted string with color to print + const char *name # Domain name + size_t namelen # strlen(name) + ctypedef Eina_Log_Domain const_Eina_Log_Domain "const Eina_Log_Domain" + #################################################################### # Other typedefs # ctypedef int (*Eina_Compare_Cb)(const_void *data1, const_void *data2) ctypedef void (*Eina_Free_Cb)(void *data) + ctypedef void (*Eina_Log_Print_Cb)(const_Eina_Log_Domain *d, + Eina_Log_Level level, + const_char *file, const_char *fnc, int line, + const_char *fmt, void *data, va_list args) #################################################################### # Functions @@ -142,3 +166,29 @@ cdef extern from "Eina.h": Eina_Bool eina_hash_add(Eina_Hash *hash, const_void *key, const_void *data) Eina_Bool eina_hash_del(Eina_Hash *hash, const_void *key, const_void *data) void *eina_hash_find(Eina_Hash *hash, const_void *key) + + void eina_log_threads_enable() + void eina_log_print_cb_set(Eina_Log_Print_Cb cb, void *data) + void eina_log_level_set(int level) + int eina_log_level_get() + Eina_Bool eina_log_main_thread_check() + void eina_log_function_disable_set(Eina_Bool disabled) + Eina_Bool eina_log_function_disable_get() + void eina_log_domain_level_set(const_char *domain_name, int level) + int eina_log_domain_level_get(const_char *domain_name) + int eina_log_domain_registered_level_get(int domain) + int eina_log_domain_register(const_char *name, const_char *color) + void eina_log_domain_unregister(int domain) + void eina_log_print(int domain, + Eina_Log_Level level, + const_char *file, + const_char *fnc, + int line, + const_char *fmt, + ...) + + void EINA_LOG_DOM_CRIT(int DOM, const_char *fmt, ...) + void EINA_LOG_DOM_ERR(int DOM, const_char *fmt, ...) + void EINA_LOG_DOM_WARN(int DOM, const_char *fmt, ...) + void EINA_LOG_DOM_INFO(int DOM, const_char *fmt, ...) + void EINA_LOG_DOM_DBG(int DOM, const_char *fmt, ...) --