##tornado-debug 原理
使用方法: $ tor-deb python -m wcms_front.server
原理流程:
-
把/usr/lib/python2.7/site-packages/tornado_debug/bootstrap添加到环境变量PYTHONPATH
-
使用os.execl开启子进程,运行python程序
-
python的site模块会执行bootstrap下的sitecustomize.py, 我们在sitecustomize.py中设置了import-hook
-
从sys.path中删除/usr/lib/python2.7/site-packages/tornado_debug/bootstrap
-
执行目标程序
##import hook 如果没有特殊设置,python会从sys.path列表中的路径下,查找module, 另外,python 还提供了两种hook方法, 可以在默认导入方法执行前使用。 ####sys.path_hooks 当导入模块时, sys.path 中的每一个路径会按顺序出入sys.path_hooks中的每个finder, 知道某个finder没有抛出ImportError,则该模块的导入会交给这个finder执行。finder 先执行 find_module, 如果找到了改模块,返回一个loader, loader执行 load_module. 当然也可以简化,将load_module 和 fnd_module的工作放到find_module, 而不返回loader。
import sys
class NoisyImportFinder(object):
PATH_TRIGGER = 'NoisyImportFinder_PATH_TRIGGER'
def __init__(self, path_entry):
print 'Checking NoisyImportFinder support for %s' % path_entry
if path_entry != self.PATH_TRIGGER:
print 'NoisyImportFinder does not work for %s' % path_entry
raise ImportError()
return
def find_module(self, fullname, path=None):
print 'NoisyImportFinder looking for "%s"' % fullname
return None
sys.path_hooks.append(NoisyImportFinder)
sys.path.insert(0, NoisyImportFinder.PATH_TRIGGER)
try:
import target_module
except Exception, e:
print 'Import failed:', e
####sys.meta_path
sys.meta_path列表内的hook 会在sys.path_hooks之前调用。 python会把代码中描述的模块的路径传入每一个sys.meta_path内的hook, 直到某个hook返回一个loader, 再使用这个loader加载模块.
class ImportHookFinder:
def __init__(self):
self._skip = {}
def find_module(self, fullname, path=None):
# If not something we are interested in we can return.
if fullname not in _import_hooks:
return None
# Check whether this is being called on the second time
# through and return.
if fullname in self._skip:
return None
# We are now going to call back into import. We set a
# flag to see we are handling the module so that check
# above drops out on subsequent pass and we don't go
# into an infinite loop.
self._skip[fullname] = True
try:
__import__(fullname)
return _ImportHookLoader()
finally:
del self._skip[fullname]
class _ImportHookLoader:
def load_module(self, fullname):
# Call the import hooks on the module being handled.
module = sys.modules[fullname]
_notify_import_hooks(fullname, module)
return module
site — Site-specific configuration hook
在python程序运行前,python环境初始化过程中自动调用。
完成工作,按照顺序为:
-
将sys.prefix 、sys.exec_prefix 和 lib/pythonX.Y/site-packages 合成module的search path.。加入sys.path。eg: /home/jay/env/tornado/lib/python2.7/site-packages
-
在添加的路径下寻找name.pth。 文件中描述了添加到sys.path的子文件夹路径。eg: 在我的/home/jay/env/tornado/lib/python2.7/site-packages下有一个newrelic.pth, 内容为"newrelic-2.46.0.37", 所以/home/jay/env/tornado/lib/python2.7/site-packages/newrelic-2.46.0.37/会被添加到sys.path。
-
import sitecustomize . sitecustomize内部可以做任意的设置。
-
import usercustomize。 usercustomize 内部做任意的设置。 但是usercustomize习惯上放在user python path 下, eg: /home/jay/.local/lib/python2.7/site-packages , 而且只有在site.ENABLE_USER_SITE == True时有效。
所以可以设置特殊的usercustomize.py文件, 在python代码执行之前,添加import hook。
boot_directory = os.path.dirname(__file__)
path = list(sys.path)
if boot_directory in path:
del path[path.index(boot_directory)]
try:
(file, pathname, description) = imp.find_module('sitecustomize', path)
except ImportError:
pass
else:
imp.load_module('sitecustomize', file, pathname, description)
from tornado_debug import agent
agent.initialize()
Written with StackEdit.