Newrelic 是APM(Application Performance Management)(应用性能管理/监控)解决方案提供商。项目中,通常用它来追踪应用的性能。最近看了一下 newrelic-python-agent 源码,这是查看源码过程中的一些记录。
目录结构
newrelic 目录结构如下:
newrelic
├── admin# 常用命令
├── api# 探针
├── bootstrap
├── common
├── core
├── extras
│ └── framework_django
│ └── templatetags
├── hooks# 数据库 web 各个库的一些探针
│ ├── framework_tornado
│ ├── framework_tornado_r3
│ └── framework_tornado_r4
├── network
├── packages
│ ├── requests
│ │ └── packages
│ │ ├── chardet
│ │ └── urllib3
│ │ ├── packages
│ │ │ └── ssl_match_hostname
│ │ └── util
│ └── wrapt
└── samplers
命令
使用可以列出所有命令:
$ newrelic-adminhelp
Usage: newrelic-admincommand[options]
Type'newrelic-admin help 'forhelpon a specific command.
Available commands are:
generate-config
license-info
license-key
local-config
network-config
record-deploy
run-program
run-python
server-config
validate-config
通过 setup.py 代码可以知道:
ifwith_setuptools:
kwargs['entry_points']={
'console_scripts':['newrelic-admin = newrelic.admin:main'],
}
命令调用的是,这是代码的入口。首先看一下目录。admin
admin 目录是 newrelic-admin help 列出的命令脚本所在目录。包含文件如下:
$ tree
admin
├── __init__.py
├── __main__.py
├── debug_console.py
├── generate_config.py
├── license_info.py
├── license_key.py
├── local_config.py
├── network_config.py
├── record_deploy.py
├── run_program.py
├── run_python.py
├── server_config.py
└── validate_config.py
的 main 函数 是命令执行的入口。文件中代码
load_internal_plugins()
load_external_plugins()
用来加载中定义的命令。run_program
首先看下 run_program 命令,这个命令使用方式如下:
newrelic-admin run-program yourcommand
中函数有装饰器 command,用来定义将命令以及相关说明添加到字典。在中代码:可以发现文件被加入到了 PYTHONPATH。python 解释器初始化的时候会自动 import下存在的和模块。之后的功能比较简单,就是调用 os 模块执行命令。现在看下代码。在 这个文件的最后一行:这里用来初始化newrelic,具体代码在文件。以下是initialize函数:
definitialize(config_file=None,environment=None,ignore_errors=None,
log_file=None,log_level=None):
ifconfig_fileisNone:
config_file=os.environ.get('NEW_RELIC_CONFIG_FILE',None)
ifenvironmentisNone:
environment=os.environ.get('NEW_RELIC_ENVIRONMENT',None)
ifignore_errorsisNone:
ignore_errors=newrelic.core.config._environ_as_bool(
'NEW_RELIC_IGNORE_STARTUP_ERRORS',True)
_load_configuration(config_file,environment,ignore_errors,
log_file,log_level)# 加载配置
if_settings.monitor_modeor_settings.developer_mode:
_settings.enabled=True
_setup_instrumentation()# 设置探针
_setup_data_source()# TODO
_setup_extensions()# TODO
_setup_agent_console()# TODO
else:
_settings.enabled=False
其中第14行是用来加载 newrelic 的相关配置。比如:日志目录、各种环境变量、秘钥、newrelic host 地址等等。`_setup_instrumentation() 中 _process_module_builtin() 用来设置探针。数据库、外部请求 等监控模块都位于 hook 目录下,通过函数将进程与监控模块进行绑定,包括 django 的主要模块以及常用的数据库等。在核心模块执行的时候触发监控,将数据回传到模块进行处理。而对于硬件信息的检测则由进行。
newrelic run_program 初始化过程
以下为 flask 应用初始化过程,其它应用类似:
代码中会把添加到,python 解释器初始化的时候会自动 import下存在的和模块
调用,函数被调用,会把需要 wrap 的包先添加到_import_hooks。
中执行
为
在代码中,使用到了第三方包,以下是 wrapt 的官方描述(文档地址)。wrapt模块的目的是为Python提供一个透明的对象代理,它可以作为构建函数包装器和装饰函数的基础。wrapt 提供了一个简单易用的decorator工厂,利用它你可以简单地创建decorator,并且在任何情况下都可以正确地使用它们。简单示例如下:
importwrapt
# 普通装饰器
@wrapt.decorator
defpass_through(wrapped,instance,args,kwargs):
returnwrapped(*args,**kwargs)
@pass_through
deffunction():
pass
# 带参数的装饰器
importwrapt
defwith_arguments(myarg1,myarg2):
@wrapt.decorator
defwrapper(wrapped,instance,args,kwargs):
returnwrapped(*args,**kwargs)
returnwrapper
@with_arguments(1,2)
deffunction():
pass
要实现decorator,需要首先定义一个装饰器函数。这将在每次调用修饰函数时调用。装饰器函数需要使用四个位置参数:
wrapped - The wrapped function which in turns needs to be called by your wrapper function.
instance - The object to which the wrapped function was bound when it was called.
args - The list of positional arguments supplied when the decorated function was called.
kwargs - The dictionary of keyword arguments supplied when the decorated function was called.
具体使用参考文档吧。文档地址newrelic 源码仔细看下去,太...复杂了。下一篇再分析一个 flask 请求到结束探针工作的完整过程吧。最后,感谢女朋友支持和包容,比❤️也可以在公号输入以下关键字获取历史文章:||
领取专属 10元无门槛券
私享最新 技术干货