1# Copyright (C) 2011, 2013 Red Hat, Inc. 2# Copyright (C) 2011 Cole Robinson <crobinso@redhat.com> 3# 4# This work is licensed under the GNU GPLv2 or later. 5# See the COPYING file in the top-level directory. 6 7# This module provides a simple way to trace any activity on a specific 8# python class or module. The trace output is logged using the regular 9# logging infrastructure. Invoke this with virt-manager --trace-libvirt 10 11import re 12import threading 13import time 14import traceback 15from types import FunctionType 16 17from virtinst import log 18 19 20CHECK_MAINLOOP = False 21 22 23def generate_wrapper(origfunc, name): 24 # This could be used as generic infrastructure, but it has hacks for 25 # identifying places where libvirt hits the network from the main thread, 26 # which causes UI blocking on slow network connections. 27 28 def newfunc(*args, **kwargs): 29 threadname = threading.current_thread().name 30 is_main_thread = (threading.current_thread().name == "MainThread") 31 32 # These APIs don't hit the network, so we might not want to see them. 33 is_non_network_libvirt_call = (name.endswith(".name") or 34 name.endswith(".UUIDString") or 35 name.endswith(".__init__") or 36 name.endswith(".__del__") or 37 name.endswith(".connect") or 38 name.startswith("libvirtError")) 39 40 if (not is_non_network_libvirt_call and 41 (is_main_thread or not CHECK_MAINLOOP)): 42 tb = "" 43 if is_main_thread: 44 tb = "\n%s" % "".join(traceback.format_stack()) 45 log.debug("TRACE %s: thread=%s: %s %s %s%s", 46 time.time(), threadname, name, args, kwargs, tb) 47 return origfunc(*args, **kwargs) 48 49 return newfunc 50 51 52def wrap_func(module, funcobj): 53 name = funcobj.__name__ 54 log.debug("wrapfunc %s %s", funcobj, name) 55 56 newfunc = generate_wrapper(funcobj, name) 57 setattr(module, name, newfunc) 58 59 60def wrap_method(classobj, methodobj): 61 name = methodobj.__name__ 62 fullname = classobj.__name__ + "." + name 63 log.debug("wrapmeth %s", fullname) 64 65 newfunc = generate_wrapper(methodobj, fullname) 66 setattr(classobj, name, newfunc) 67 68 69def wrap_class(classobj): 70 log.debug("wrapclas %s %s", classobj, classobj.__name__) 71 72 for name in dir(classobj): 73 obj = getattr(classobj, name) 74 if isinstance(obj, FunctionType): 75 wrap_method(classobj, obj) 76 77 78def wrap_module(module, mainloop, regex): 79 global CHECK_MAINLOOP 80 CHECK_MAINLOOP = mainloop 81 for name in dir(module): 82 if regex and not re.match(regex, name): 83 continue # pragma: no cover 84 obj = getattr(module, name) 85 if isinstance(obj, FunctionType): 86 wrap_func(module, obj) 87 if isinstance(obj, type): 88 wrap_class(obj) 89