博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
newrelic python agent 源码分析-1
阅读量:5934 次
发布时间:2019-06-19

本文共 5716 字,大约阅读时间需要 19 分钟。

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-admin help 可以列出所有命令:

$ newrelic-admin helpUsage: newrelic-admin command [options]Type 'newrelic-admin help 'for help on 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 代码可以知道:

if with_setuptools:    kwargs['entry_points'] = {            'console_scripts': ['newrelic-admin = newrelic.admin:main'],            }复制代码

newrelic-admin 命令调用的是 newrelic.admin:main,这是代码的入口。首先看一下 newrelic/admin/目录。

admin

admin 目录是 newrelic-admin help 列出的命令脚本所在目录。

包含文件如下:

$ treeadmin├── __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复制代码

__init__.py 的 main 函数 是命令执行的入口。

__init__.py 文件中代码

load_internal_plugins()load_external_plugins()复制代码

用来加载 _builtin_plugins 中定义的命令。

run_program

首先看下 run_program 命令,这个命令使用方式如下:

newrelic-admin run-program your command复制代码

newrelic/admin/run_program.pyrun_program 函数有装饰器 command,用来定义将命令以及相关说明添加到字典 _commands

run_program 中代码:

root_directory = os.path.dirname(root_directory)boot_directory = os.path.join(root_directory, 'bootstrap')if 'PYTHONPATH' in os.environ:    path = os.environ['PYTHONPATH'].split(os.path.pathsep)    if not boot_directory in path:        python_path = "%s%s%s" % (boot_directory, os.path.pathsep, os.environ['PYTHONPATH'])os.environ['PYTHONPATH'] = python_path复制代码

可以发现newrelic/bootstrap/sitecustomize.py 文件被加入到了 PYTHONPATH。

python 解释器初始化的时候会自动 import PYTHONPATH 下存在的 sitecustomizeusercustomize 模块。

之后的功能比较简单,就是调用 os 模块执行命令。

现在看下newrelic/bootstrap/sitecustomize.py 代码。

在 这个文件的最后一行:

newrelic.config.initialize(config_file, environment)复制代码

这里用来初始化newrelic,具体代码在 newrelic/config.py文件。

以下是initialize函数:

def initialize(config_file=None, environment=None, ignore_errors=None,            log_file=None, log_level=None):    if config_file is None:        config_file = os.environ.get('NEW_RELIC_CONFIG_FILE', None)    if environment is None:        environment = os.environ.get('NEW_RELIC_ENVIRONMENT', None)    if ignore_errors is None:        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_mode or _settings.developer_mode:        _settings.enabled = True        _setup_instrumentation()  # 设置探针        _setup_data_source()  # TODO        _setup_extensions()   # TODO        _setup_agent_console()   # TODO    else:        _settings.enabled = False复制代码

其中第14行 _load_configuration 是用来加载 newrelic 的相关配置。比如:日志目录、各种环境变量、秘钥、newrelic host 地址等等。

`_setup_instrumentation() 中 _process_module_builtin() 用来设置探针。

数据库、外部请求 等监控模块都位于 hook 目录下,通过 _process_module_builtin 函数将进程与监控模块进行绑定,包括 django 的主要模块以及常用的数据库等。在核心模块执行的时候触发监控,将数据回传到 api.time_trace 模块进行处理。

而对于硬件信息的检测则由 commo.system_info 进行。

newrelic run_program 初始化过程

以下为 flask 应用初始化过程,其它应用类似:

  1. newrelic/admin/__init__.py main()
  2. newrelic/admin/run_program.py 代码中会把 newrelic/bootstrap/sitecustomize.py 添加到 PYTHONPATH,python 解释器初始化的时候会自动 import PYTHONPATH 下存在的 sitecustomizeusercustomize 模块
  3. newrelic/bootstrap/sitecustomize.py 调用 newrelic.config.initialize()_setup_instrumentation() 函数被调用,_process_module_builtin会把需要 wrap 的包先添加到_import_hooks。
  4. newrelic/config.pysys.meta_path.insert(0, newrelic.api.import_hook.ImportHookFinder()) 执行
  5. newrelic/api/import_hook.py ImportHookFinder().find_model()
  6. newrelic/api/import_hook.py _ImportHookLoader() or _ImportHookChainedLoader()
  7. newrelic/api/import_hook.py _notify_import_hooks callablenewrelic/config _module_import_hook _instrument
  8. newrelic/hooks/framework_flask.py instrument_flask_app
  9. newrelic/api/web_transaction.py wrap_wsgi_application
  10. newrelic/common/object_wrapper.py wrap_object

在代码中,使用到了第三方包 wrapt,以下是 wrapt 的官方描述()。

wrapt模块的目的是为Python提供一个透明的对象代理,它可以作为构建函数包装器和装饰函数的基础。wrapt 提供了一个简单易用的decorator工厂,利用它你可以简单地创建decorator,并且在任何情况下都可以正确地使用它们。

wrapt简单示例如下:

import wrapt# 普通装饰器@wrapt.decoratordef pass_through(wrapped, instance, args, kwargs):    return wrapped(*args, **kwargs)@pass_throughdef function():    pass# 带参数的装饰器import wraptdef with_arguments(myarg1, myarg2):    @wrapt.decorator    def wrapper(wrapped, instance, args, kwargs):        return wrapped(*args, **kwargs)    return wrapper@with_arguments(1, 2)def function():    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 请求到结束探针工作的完整过程吧。

如果下一篇一直没写,那应该是看不下去了。

最后,感谢女朋友支持和包容,比❤️

也可以在公号输入以下关键字获取历史文章:公号&小程序 | 设计模式 | 并发&协程

转载地址:http://ujjtx.baihongyu.com/

你可能感兴趣的文章
java常见数据结构举例
查看>>
hadoop 2.2.0 编译报错: [ERROR] class file for org.mortbay.component.AbstractLifeCycle not found
查看>>
erlang入门之编译和运行
查看>>
listView优化方案
查看>>
模块化编程时中断函数的处理
查看>>
Android 4.2 通知通过PendingIntent启动Activity失败的问题
查看>>
UITabBarController详解
查看>>
SQL Server 找出值得优化的语句
查看>>
apache2.2 虚拟主机配置
查看>>
算术和关系运算符重载
查看>>
破解中国电信华为无线猫路由(HG522-C)自己主动拨号+不限电脑数+iTV
查看>>
汽车必备车饰和常用物品
查看>>
DHCP Option 60 的理解
查看>>
JPA JPQL 查询、排序.....(转)
查看>>
SQL中实现SPLIT函数几种方法
查看>>
常用数学函数篇abs acos asin atan ceil cos exp frexp ldexp log pow sin sinh sqrt tan tanh
查看>>
认真过好你的二十几岁
查看>>
nssm在windows服务器上部署nodejs,coffee启动方式
查看>>
WebService安全加密
查看>>
cocos2dx中的一些坑
查看>>