What is the python equivalent of g_log_set_handler when using GLib from python

Question:

I want to set the log level in my python glib project. Therefore I am looking for the g_log_set_handler() equivalent when using GLib from python via gi.repository.

But the expected GLib.log_set_handler function seems to be missing. Here is a sample output of my python shell:

~$ python
Python 2.7.3 (default, Apr 10 2013, 06:20:15) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from gi.repository import GLib 
>>> GLib.log_set_fatal_mask
<function log_set_fatal_mask at 0x2a7b668> 
>>> GLib.log_set_handler
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/gi/module.py", line 316, in __getattr__
    attr = super(DynamicGLibModule, self).__getattr__(name)
  File "/usr/lib/python2.7/dist-packages/gi/module.py", line 243, in __getattr__
     return getattr(self._introspection_module, name)
  File "/usr/lib/python2.7/dist-packages/gi/module.py", line 105, in __getattr__
    self.__name__, name))
  AttributeError: 'gi.repository.GLib' object has no attribute 'log_set_handler'
>>> 

As one can see, GLib from the introspection repository is found and the log_set_fatal_mask function exists (which is the equivalent of the g_log_set_fatal_mask). But log_set_handler is not found.

Why is that and how could I correctly set my loglevel from within python?

Asked By: Dynalon

||

Answers:

I found out this is currently not possible and a known bug within either gobject-introspection or glib, since g_log_set_handler is not bindable.

See:
https://bugzilla.gnome.org/show_bug.cgi?id=670507

Answered By: Dynalon

Recently I got into this problem, and solved using ctypes, like the following example.

from ctypes import CDLL, CFUNCTYPE, POINTER, Structure, 
    c_int, c_uint, c_size_t, c_void_p, c_char_p
from gi.repository import GLib

libglib = CDLL('libglib-2.0.so.0')
def c_func(func, ret_type, *arg_types):
    func.restype = ret_type
    func.argtypes = arg_types

log_func_t = CFUNCTYPE(None, c_char_p, c_int, c_char_p, c_void_p)
c_func(libglib.g_log, None, c_char_p, c_int, c_char_p)
c_func(libglib.g_log_set_handler, c_uint, c_char_p, c_int, log_func_t, c_void_p)

@log_func_t
def log_func(domain, level, msg, data):
    print('log', domain, level, msg, data)

libglib.g_log_set_handler(None, 0x7f, log_func, None)
libglib.g_log(None, GLib.LogLevelFlags.LEVEL_MESSAGE, b'aaa')

But the modern GLib introduced the structured logging, and you need to call g_log_set_writer_func() to capture all messages. This also can be done with ctypes, but I’ll omit that because it’s out of the scope of this question.(It’s much more complex than the above.)

Answered By: relent95