资讯专栏INFORMATION COLUMN

newrelic python agent 源码分析-1

szysky / 1648人阅读

摘要:是应用性能管理监控解决方案提供商。目录是列出的命令脚本所在目录。包含文件如下的函数是命令执行的入口。而对于硬件信息的检测则由进行。文档地址源码仔细看下去,太复杂了。下一篇再分析一个请求到结束探针工作的完整过程吧。

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 help

Usage: 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 列出的命令脚本所在目录。

包含文件如下:

$ 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

__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 应用初始化过程,其它应用类似:

newrelic/admin/__init__.py main()

newrelic/admin/run_program.py 代码中会把 newrelic/bootstrap/sitecustomize.py 添加到 PYTHONPATH,python 解释器初始化的时候会自动 import PYTHONPATH 下存在的 sitecustomizeusercustomize 模块

newrelic/bootstrap/sitecustomize.py 调用 newrelic.config.initialize()_setup_instrumentation() 函数被调用,_process_module_builtin会把需要 wrap 的包先添加到_import_hooks。

newrelic/config.pysys.meta_path.insert(0, newrelic.api.import_hook.ImportHookFinder()) 执行

newrelic/api/import_hook.py ImportHookFinder().find_model()

newrelic/api/import_hook.py _ImportHookLoader() or _ImportHookChainedLoader()

newrelic/api/import_hook.py _notify_import_hooks callablenewrelic/config _module_import_hook _instrument

newrelic/hooks/framework_flask.py instrument_flask_app

newrelic/api/web_transaction.py wrap_wsgi_application

newrelic/common/object_wrapper.py wrap_object

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

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

wrapt简单示例如下:

import wrapt
# 普通装饰器
@wrapt.decorator
def pass_through(wrapped, instance, args, kwargs):
    return wrapped(*args, **kwargs)

@pass_through
def function():
    pass

# 带参数的装饰器
import wrapt

def 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 请求到结束探针工作的完整过程吧。

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

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/41726.html

相关文章

  • Python 探针实现原理

    摘要:本文将简单讲述一下探针的实现原理。探针的实现主要涉及以下几个知识点这个简单的来说就是可以实现的功能,当执行相关的操作时,会触发列表中定义的对象。当然,跟实际使用的探针程序相比肯定是有很大的差距的,这篇文章主要是讲解一下探针背后的实现原理。 本文将简单讲述一下 Python 探针的实现原理。 同时为了验证这个原理,我们也会一起来实现一个简单的统计指定函数执行时间的探针程序。 探针的实现主...

    littleGrow 评论0 收藏0
  • 监控系统的前世今生

    摘要:本文主要分为三个部分,将介绍监控系统的历史流派及如何选型,希望对读者能有所帮助。图监控系统发展历史早期的监控系统互联网发展早期的监控系统,主要是指基于简单网络管理协议的网络监控和系统主要指操作系统监控。 本文作者 刘俊微博平台监控技术负责人,负责微博平台、PC微博大规模监控系统的建设,主要关注实时大数据、运维自动化、智能化方向,2014年加入微博,之前曾在新浪、搜狐等公司从事运维监控方面的工...

    iKcamp 评论0 收藏0
  • 手把手教你搭APM之Skywalking搭建指南(支持Java/C#/Node.js)

    摘要:通过跟踪请求的处理过程,来对应用系统在前后端处理服务端调用的性能消耗进行跟踪,关于的介绍可以看这个链接,大规模分布式系统的跟踪系统作者刀把五链接来源知乎著作权归作者所有。 手把手教你搭APM之Skywalking 前言 什么是APM?全称:Application Performance Management 可以参考这里: 现代APM体系,基本都是参考Google的Dapper(大规模...

    ingood 评论0 收藏0
  • 容器监控实践—开篇

    摘要:方案汇总一开源方案采集展示报警二商业方案三云厂商腾讯云阿里云百度云华为云四主机监控五日志监控六服务监控七存储后端脑图本文为容器监控实践系列文章,完整内容见 概述 随着越来越多的线上服务docker化,对容器的监控、报警变得越来越重要,容器监控有多种形态,有些是开源的(如promethues),而另一些则是商业性质的(如Weave),有些是集成在云厂商一键部署的(Rancher、谷歌云)...

    Zack 评论0 收藏0
  • 容器监控实践—开篇

    摘要:方案汇总一开源方案采集展示报警二商业方案三云厂商腾讯云阿里云百度云华为云四主机监控五日志监控六服务监控七存储后端脑图本文为容器监控实践系列文章,完整内容见 概述 随着越来越多的线上服务docker化,对容器的监控、报警变得越来越重要,容器监控有多种形态,有些是开源的(如promethues),而另一些则是商业性质的(如Weave),有些是集成在云厂商一键部署的(Rancher、谷歌云)...

    hellowoody 评论0 收藏0

发表评论

0条评论

szysky

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<