2013-10-28 00:59:46 +04:00
# Copyright (C) 2011, 2013 Red Hat, Inc.
2012-09-27 16:58:54 +04:00
# Copyright (C) 2011 Cole Robinson <crobinso@redhat.com>
#
2018-04-04 16:35:41 +03:00
# This work is licensed under the GNU GPLv2 or later.
2018-03-20 22:00:02 +03:00
# See the COPYING file in the top-level directory.
2012-09-27 16:58:54 +04:00
# This module provides a simple way to trace any activity on a specific
# python class or module. The trace output is logged using the regular
# logging infrastructure. Invoke this with virt-manager --trace-libvirt
import logging
import re
2014-09-13 21:52:42 +04:00
import threading
import time
2012-09-27 16:58:54 +04:00
import traceback
from types import FunctionType
2018-10-10 22:19:15 +03:00
CHECK_MAINLOOP = False
2012-09-27 16:58:54 +04:00
2013-04-13 22:34:52 +04:00
2014-09-13 21:52:42 +04:00
def generate_wrapper ( origfunc , name ) :
# This could be used as generic infrastructure, but it has hacks for
# identifying places where libvirt hits the network from the main thread,
# which causes UI blocking on slow network connections.
2012-09-27 16:58:54 +04:00
def newfunc ( * args , * * kwargs ) :
2014-09-13 21:52:42 +04:00
threadname = threading . current_thread ( ) . name
is_main_thread = ( threading . current_thread ( ) . name == " MainThread " )
# These APIs don't hit the network, so we might not want to see them.
is_non_network_libvirt_call = ( name . endswith ( " .name " ) or
name . endswith ( " .UUIDString " ) or
name . endswith ( " .__init__ " ) or
name . endswith ( " .__del__ " ) or
name . endswith ( " .connect " ) or
name . startswith ( " libvirtError " ) )
2018-10-10 22:19:15 +03:00
if ( not is_non_network_libvirt_call and
( is_main_thread or not CHECK_MAINLOOP ) ) :
2014-09-13 21:52:42 +04:00
tb = " "
if is_main_thread :
tb = " \n %s " % " " . join ( traceback . format_stack ( ) )
logging . debug ( " TRACE %s : thread= %s : %s %s %s %s " ,
time . time ( ) , threadname , name , args , kwargs , tb )
2012-09-27 16:58:54 +04:00
return origfunc ( * args , * * kwargs )
return newfunc
2013-04-13 22:34:52 +04:00
2014-09-13 21:52:42 +04:00
def wrap_func ( module , funcobj ) :
2012-09-27 16:58:54 +04:00
name = funcobj . __name__
2012-10-21 21:12:21 +04:00
logging . debug ( " wrapfunc %s %s " , funcobj , name )
2012-09-27 16:58:54 +04:00
2014-09-13 21:52:42 +04:00
newfunc = generate_wrapper ( funcobj , name )
2012-09-27 16:58:54 +04:00
setattr ( module , name , newfunc )
2013-04-13 22:34:52 +04:00
2014-09-13 21:52:42 +04:00
def wrap_method ( classobj , methodobj ) :
2012-09-27 16:58:54 +04:00
name = methodobj . __name__
fullname = classobj . __name__ + " . " + name
2012-10-21 21:12:21 +04:00
logging . debug ( " wrapmeth %s " , fullname )
2012-09-27 16:58:54 +04:00
2014-09-13 21:52:42 +04:00
newfunc = generate_wrapper ( methodobj , fullname )
2012-09-27 16:58:54 +04:00
setattr ( classobj , name , newfunc )
2013-04-13 22:34:52 +04:00
2014-09-13 21:52:42 +04:00
def wrap_class ( classobj ) :
2012-10-21 21:12:21 +04:00
logging . debug ( " wrapclas %s %s " , classobj , classobj . __name__ )
2012-09-27 16:58:54 +04:00
for name in dir ( classobj ) :
obj = getattr ( classobj , name )
2018-10-10 22:19:15 +03:00
if isinstance ( obj , FunctionType ) :
2014-09-13 21:52:42 +04:00
wrap_method ( classobj , obj )
2012-09-27 16:58:54 +04:00
2013-04-13 22:34:52 +04:00
2018-10-10 22:19:15 +03:00
def wrap_module ( module , mainloop , regex ) :
global CHECK_MAINLOOP
CHECK_MAINLOOP = mainloop
2012-09-27 16:58:54 +04:00
for name in dir ( module ) :
if regex and not re . match ( regex , name ) :
continue
obj = getattr ( module , name )
2017-10-11 14:35:41 +03:00
if isinstance ( obj , FunctionType ) :
2014-09-13 21:52:42 +04:00
wrap_func ( module , obj )
2018-02-07 02:57:00 +03:00
if isinstance ( obj , type ) :
2014-09-13 21:52:42 +04:00
wrap_class ( obj )