@@ -7,6 +7,13 @@ class Instance:
7
7
- a list of strings as first parameters
8
8
- the parameters given as the constructor parameters (must be strings)
9
9
"""
10
+
11
+ # logging related private fields
12
+ _vsnprintf = None
13
+ _max_log_message_size = 4096
14
+ _logger = None
15
+ _log_handler = None
16
+
10
17
def __new__ (cls , * args ):
11
18
if len (args ) == 1 :
12
19
# Only 1 arg. It is either a C pointer, or an arg string,
@@ -142,6 +149,54 @@ def video_filter_list_get(self):
142
149
"""
143
150
return module_description_list (libvlc_video_filter_list_get (self ))
144
151
152
+ def set_logger (self , logger , max_log_message_size = 4096 ):
153
+ """Links a logging.Logger object to the libVLC Instance
154
+
155
+ Along with the log level and message, each libVLC log will also include
156
+ The following extra info:
157
+ - vlc_module: the name of the VLC module (str).
158
+ - file: the VLC source filename (str).
159
+ - line: the VLC source file line number (int).
160
+ These variables can be used in the logger formatter.
161
+
162
+ @param logger: a logging.Logger object
163
+ @param max_log_message_size: defines the maximum size that will be
164
+ copied from VLC log messages. If you experience truncated log
165
+ messages, raise this number (default 4096).
166
+ """
167
+ # libVLC provides the log message through a printf format + va_list.
168
+ # Unfortunately, there is no simple way to use a
169
+ # printf format + va_list in Python outside of the use of a C format
170
+ # function.
171
+ # As there is no guarantee to have access to a C `vasprintf`, we use
172
+ # `vsnprintf` with a log message max size.
173
+ libc = find_libc ()
174
+ if libc is None :
175
+ raise Exception ("Cannot find a proper standard C library (needed to retrieve log messages)" )
176
+ self ._vsnprintf = libc .vsnprintf
177
+ self ._max_log_message_size = max_log_message_size
178
+ self ._logger = logger
179
+ # The log_handler is meant to be the "real" callback for libvlc_log_set().
180
+ @CallbackDecorators .LogCb
181
+ def log_handler (instance , log_level , ctx , fmt , va_list ):
182
+ bufferString = ctypes .create_string_buffer (self ._max_log_message_size )
183
+ self ._vsnprintf (bufferString , self ._max_log_message_size , fmt ,
184
+ ctypes .cast (va_list , ctypes .c_void_p ))
185
+ msg = bufferString .value .decode ('utf-8' )
186
+ module , file , line = libvlc_log_get_context (ctx )
187
+ module = module .decode ('utf-8' )
188
+ file = file .decode ('utf-8' )
189
+ self ._logger .log (loglevel_to_logging (LogLevel (log_level )),
190
+ msg , extra = {"vlc_module" : module , "file" : file , "line" : line })
191
+ # We need to keep a reference to the log_handler function that persists
192
+ # after the end of the set_logger.
193
+ # If we do not do that, there is a (high) chance the python garbage
194
+ # collector will destroy the callback function and produce segfault in
195
+ # libVLC.
196
+ # To avoid that, link the log_handler lifetime to the Instance's one.
197
+ self ._log_handler = log_handler
198
+ self .log_set (self ._log_handler , None )
199
+
145
200
class Media :
146
201
"""Create a new Media instance.
147
202
0 commit comments