1313# limitations under the License.
1414
1515import asyncio
16+ import logging
1617import ctypes
1718import os
1819import platform
2425from ._proto import ffi_pb2 as proto_ffi
2526from ._utils import Queue
2627
28+ logger = logging .getLogger ("livekit" )
29+
2730
2831def get_ffi_lib_path ():
2932 # allow to override the lib path using an env var
@@ -121,9 +124,39 @@ def ffi_event_callback(
121124 event_data = bytes (data_ptr [: int (data_len )])
122125 event = proto_ffi .FfiEvent ()
123126 event .ParseFromString (event_data )
127+
128+ which = event .WhichOneof ("message" )
129+ if which == "logs" :
130+ for record in event .logs .records :
131+ logger .log (
132+ to_python_level (record .level ),
133+ "%s:%s:%s - %s" ,
134+ record .target ,
135+ record .line ,
136+ record .module_path ,
137+ record .message ,
138+ )
139+
140+ return # no need to queue the logs
141+
124142 ffi_client .queue .put (event )
125143
126144
145+ def to_python_level (level : proto_ffi .LogLevel .ValueType ) -> int :
146+ if level == proto_ffi .LogLevel .LOG_ERROR :
147+ return logging .ERROR
148+ elif level == proto_ffi .LogLevel .LOG_WARN :
149+ return logging .WARN
150+ elif level == proto_ffi .LogLevel .LOG_INFO :
151+ return logging .INFO
152+ elif level == proto_ffi .LogLevel .LOG_DEBUG :
153+ return logging .DEBUG
154+ elif level == proto_ffi .LogLevel .LOG_TRACE :
155+ return logging .DEBUG
156+
157+ raise Exception ("unreachable" )
158+
159+
127160class FfiClient :
128161 def __init__ (self ) -> None :
129162 self ._lock = threading .RLock ()
@@ -133,6 +166,7 @@ def __init__(self) -> None:
133166 req = proto_ffi .FfiRequest ()
134167 cb_callback = int (ctypes .cast (ffi_event_callback , ctypes .c_void_p ).value ) # type: ignore
135168 req .initialize .event_callback_ptr = cb_callback
169+ req .initialize .capture_logs = True # capture logs on Python
136170 self .request (req )
137171
138172 @property
0 commit comments