基于 Python 探针完成调用库的数据提取

 

前记

最近在完善公司的监控系统, 发现在项目运行时经常会出现一些运行时的问题, 这些问题往往不是一个子服务引发的问题, 而可能是某个环节出现了问题, 这时候就需要引入APM系统。

在收集APM数据时发现在 Python 生态中针对web框架都有完善的APM中间件用于接口统计与监控, 但是第三方调用库相关的APM实现都比较少(几乎没有), 同时这些库大多数也都没提供一些钩子实现。这就需要自己去封装一些库, 为这些库实现一套调用过程的数据提供逻辑。

本文是以 Python 的 aiomysql 库为例,阐述如何基于 Python 的探针完成调用库的调用过程统计与监控的封装。

注: 监控的形式的agent有很多种,如 Prometheus , Zabbix ,  Graphite 和 Opentracing 他们的数据源有很大的不同,但是他们都是基于元数据封装成自己的源数据,然后发送到对应的服务,所以本文只介绍如何提取元数据,剩下的如何发送需要自己按照特定的监控系统去实现。注:这里以aiomysql库来做示例,提取数据的方法应该用统一的dbapi2, 本文只阐述如何简单的实现。

1.简单粗暴的方法--对mysql库进行封装

要统计一个执行过程, 就需要知道这个执行过程的开始位置和结束位置, 所以最简单粗暴的方法就是基于要调用的方法进行封装,在框架调用 MySQL 库和 MySQL 库中间实现一个中间层, 在中间层完成耗时统计,如:

# 伪代码

def my_execute(conn, sql, param):
    # 针对MySql库的统计封装组件
    with MyTracer(conn, sql, param):
        # 以下为正常使用MySql库的代码
        with conn.cursor as cursor:
            cursor.execute(sql, param)
            ...

看样子实现起来非常不错, 而且更改非常方便, 但由于是在最顶层的API上进行修改, 其实是非常不灵活的, 同时在 cursor.execute 里会进行一些预操作, 如把sql和param进行拼接, 调用 nextset 清除当前游标的数据等等。我们最后拿到的数据如时间耗时也是不准确的, 同时也没办法得到一些详细的元数据, 如错误码等等.

如果要拿到最直接有用的数据,就只能去改源代码, 然后再调用源代码了, 但是如果每个库都需要改源代码才能统计, 那也太麻烦了, 好在 Python 也提供了一些类似探针的接口, 可以通过探针把库的源码进行替换完成我们的代码.

2.Python的探针

在 Python 中可以通过 sys.meta_path 来实现 import hook 的功能, 当执行 import 相关操作时, 会根据 sys.meta_path 定义的对象对import相关库进行更改.

sys.meta_path 中的对象需要实现一个 find_module 方法, 这个 find_module 方法返回 None 或一个实现了 load_module 方法的对象, 我们可以通过这个对象, 针对一些库在import时, 把相关的方法进行替换, 简单用法如下,通过hook time.sleep 让他在sleep的时候能打印消耗的时间.

github源码存储: https://github.com/so1n/example/blob/master/example_python/example_python/python_hook/hook_demo

import importlib
import sys
from functools import wraps


def func_wrapper(func):
    """这里通过一个装饰器来达到狸猫换太子和获取数据的效果"""
    @wraps(func)
    def wrapper(*args, **kwargs):
        # 记录开始时间
        start = time.time()
        result = func(*args, **kwargs)
        # 统计消耗时间
        end = time.time()
        print(f"speed time:{end - start}")
        return result
    return wrapper


class MetaPathFinder:

    def find_module(self, fullname, path=None):
        # 执行时可以看出来在import哪些模块
        print(f&#
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值