pinpoint-php-aop 内部原理

news/2024/11/18 14:36:08/文章来源:https://www.cnblogs.com/eeliu/p/18388648

pinpoint-php-aop 是一个支持pinpoint-php agent 的库

  1. 自动注入PHP内置函数,比如redis,pdo,mysqli
  2. 自动注入用户类,比如 guzzlehttp, predis

怎样处理内置函数

内置函数解释:

    PHP comes standard with many functions and constructs. There are also functions that require specific PHP extensions compiled in, otherwise fatal "undefined function" errors will appear. For example, to use image functions such as imagecreatetruecolor(), PHP must be compiled with GD support. Or, to use mysqli_connect(), PHP must be compiled with MySQLi support. There are many core functions that are included in every version of PHP, such as the string and variable functions. A call to phpinfo() or get_loaded_extensions() will show which extensions are loaded into PHP. Also note that many extensions are enabled by default and that the PHP manual is split up by extension. ...> https://www.php.net/manual/en/functions.internal.php#functions.internal
 

通过修改PHP内核中 CG(class_table)

Inspired by https://www.phpinternalsbook.com/php7/extensions_design/hooks.html#overwriting-an-internal-function

PHP内核中提供了全局的 class_table,用户可以可以用来替换原始的函数,然后达到包装该函数的目的:比如插入一些安全的插件代码。

步骤

  1. ext_pinpoint-php 提供内置函数替换功能
// https://github.com/pinpoint-apm/pinpoint-c-agent/blob/9c544f139665dde3a9cee2a244a9c3be2f32bff9/src/PHP/pinpoint_php.cpp#L887
zend_function *func = (zend_function *)zend_hash_str_find_ptr(CG(function_table), ZSTR_VAL(name), ZSTR_LEN(name));if (func != NULL &&func->internal_function.handler == pinpoint_interceptor_handler_entry) {pp_trace("function `%s` interceptor already added", ZSTR_VAL(name));} else if (func != NULL) {pp_interceptor_v_t *interceptor =make_interceptor(name, before, end, exception, func);// insert into hashif (!zend_hash_add_ptr(PPG(interceptors), name, interceptor)) {free_interceptor(interceptor);pp_trace("added interceptor on `function`: %s failed. reason: already ""exist ",ZSTR_VAL(name));return;}func->internal_function.handler = pinpoint_interceptor_handler_entry;pp_trace("added interceptor on `function`: %s success", ZSTR_VAL(name));
 
  1. 基于第一步的功能,在插入点添加pinpoint的业务逻辑插件
// https://github.com/pinpoint-apm/pinpoint-php-aop/blob/5994253869d516c38d528a8ef784a5c1c18b20f3/lib/Pinpoint/Plugins/SysV2/_curl/curl.php#L78
pinpoint_join_cut(["curl_close"],function ($ch) use (&$ch_res) {unset($ch_res[(int) $ch]);pinpoint_start_trace();pinpoint_add_clue(PP_INTERCEPTOR_NAME, "curl_close");pinpoint_add_clue(PP_SERVER_TYPE, PP_PHP_METHOD);},function ($ret) {pinpoint_end_trace();},function ($e) {}
);
 
  1. 根据需要,启用插件
// https://github.com/pinpoint-apm/pinpoint-php-aop/blob/5994253869d516c38d528a8ef784a5c1c18b20f3/lib/Pinpoint/Plugins/PinpointPerRequestPlugins.php#L126C12-L126C58
if(sampled){require_once __DIR__ . "/SysV2/__init__.php";
}else{require_once __DIR__ . "/SysV2/_curl/__init__.php";
}
 

怎样处理用户定义的类

在此之前,你需要了解类加载器

By registering autoloaders, PHP is given a last chance to load the class or interface before it fails with an error.
> https://www.php.net/manual/en/language.oop5.autoload.php 
 

对于PHP,当用户通过 use 等来加载类或者函数的时候,内核会检查这个类是否已经被加载。如果没有,它就会调用auto_loader去调用对应的文件。pinpoint-php-aop 也就是在这个时候开始拦截类的。

  1. 当PHP的类加载器初始完成后,pinpoint-php-aop 的类加载器会拦截所有的加载的类和函数。当发现一个需要被拦截的类被加载的时候,它会把这个类指向一个添加了pinpoint插件的类。

  2. 当pinpoint 加载器发现这个文件没有被pinpoint的插件拦截,它就会生成一个添加了pinpoint插件的类,然后注册到类加载器里面。更重要的是,这些类会被缓存到cache_dir中,当后续的请求到来的时候,这些类文件会被重新使用。这样的好处是,可以节约很多请求时间。

ast_loader

可能有些晕 🥴 我用一个例子 Pinpoint\Plugins\autoload\_MongoPlugin 再来介绍一个整个流程。

步骤

  1. 比如项目里使用了mongodb client
//https://github.com/pinpoint-apm/pinpoint-c-agent/blob/9c544f139665dde3a9cee2a244a9c3be2f32bff9/testapps/SimplePHP/run.php#L92-L93$client = new MongoDB\Client("mongodb://$mongodb_host:27017");
 
  1. 通过pinpoint-php-aop 提供的函数,注册拦截 MongoDB\Client类中的__construct方法和对应的插件
//https://github.com/pinpoint-apm/pinpoint-php-aop/blob/5994253869d516c38d528a8ef784a5c1c18b20f3/lib/Pinpoint/Plugins/autoload/_MongoPlugin/__init__.php#L25
$classHandler = new AspectClassHandle(\MongoDB\Client::class);
$classHandler->addJoinPoint('__construct', MongoPlugin::class);
$cls[] = $classHandler;
 
  1. 当pinpoint完成初始化后,你会在这个路径 /tmp/.cache/__class_index.php 找到一个文件

default cache directory is /tmp/

$pinpoint_class_map = array('MongoDB\\Client' => '/tmp/.cache/MongoDB/Client.php', ...);
return $pinpoint_class_map;
 

里面还有加入了pinpoint 插件后的类的文件

//Client.php
namespace MongoDB;
class Client{
...// origin methodspublic function __pinpoint____construct(?string $uri = null, array $uriOptions = [], array $driverOptions = []){}// rendered methods public function __construct(?string $uri = null, array $uriOptions = [], array $driverOptions = []){$_pinpoint___construct_var = new \Pinpoint\Plugins\autoload\_MongoPlugin\MongoPlugin(__METHOD__, $this, $uri, $uriOptions, $driverOptions);try {$_pinpoint___construct_var->onBefore();$this->__pinpoint____construct($uri, $uriOptions, $driverOptions);$_pinpoint___construct_var->onEnd($_pinpoint___construct_ret);} catch (\Exception $e) {$_pinpoint___construct_var->onException($e);throw $e;}}
...
}
 
  1. 当上面的类(client.php)被加载到PHP的内核后,就意味着pinpoint 插件已经在你的项目里面正常工作了

i.e. 到此,用户自定义类也被加载pinpoint拦截成功了。

 

From https://github.com/pinpoint-apm/pinpoint-php-aop/wiki/pinpoint-php-aop-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/789599.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从代码到产品,我的IT职业成长之路

每个人的职业生涯都是一段充满转折和挑战的旅程,当然每一次职业转型都是一次重新定义自己的机会,从2015年开始,当时我刚踏入IT行业,成为一名Java开发者,后来随着时间的推移,我的职业方向逐渐转向了前端开发者,埋头于代码的世界。最终在2018年找到了属于自己的职业定位—…

1-0.AI工具

1-0.AI工具 一. 我知道或使用过的AI大模型平台 1. OpenAI 平台: OpenAI GPT 特点: 提供先进的自然语言处理能力,支持对话生成、文本总结、翻译等。包括GPT-3、GPT-4等版本。 2. Google AI 平台: Google Cloud AI 特点: 提供全面的AI和机器学习服务,包括AutoML、自然语言处理、…

折腾 Quickwit,Rust 编写的分布式搜索引擎 - 可观测性之分布式追踪

概述 分布式追踪是一种跟踪应用程序请求流经不同服务(如前端、后端、数据库等)的过程。它是一个强大的工具,可以帮助您了解应用程序的工作原理并调试性能问题。 Quickwit 是一个用于索引和搜索非结构化数据的云原生引擎,这使其非常适合用作追踪数据的后端。 此外,Quickwit…

POA:已开源,蚂蚁集团提出同时预训练多种尺寸网络的自监督范式 | ECCV 2024

论文提出一种新颖的POA自监督学习范式,通过弹性分支设计允许同时对多种尺寸的模型进行预训练。POA可以直接从预训练teacher生成不同尺寸的模型,并且这些模型可以直接用于下游任务而无需额外的预训练。这个优势显著提高了部署灵活性,并有助于预训练的模型在各种视觉任务中取得…

【信息收集】旁站和C段

一、 站长之家二、 google hacking2.1 网络空间搜索引擎2.2 在线c段 webscan.cc2.3 Nmap,Msscan扫描等2.4 常见端口表旁站往往存在业务功能站点,建议先收集已有IP的旁站,再探测C段,确认C段目标后,再在C段的基础上再收集一次旁站。 旁站是和已知目标站点在同一服务器但不同端…

茂名工厂智能视频监控系统

茂名工厂智能视频监控系统除开监控出入工作人员外,还必须监控车子,以追踪出入时长。除开组装超清精彩短视频监控监控摄像头外,茂名工厂智能视频监控系统还必须组装车辆识别系统和智能安全通道。办公室一般是一个主要的信息内容,在安装视频监控时,也需要考虑到防盗系统系统…

【信息收集】查找真实ip

一、 多地ping确认是否使用CDN二、查询历史DNS解析记录2.1 DNSDB2.2 微步在线2.3 Ipip.net2.4 viewdns三、phpinfo四、绕过CDN如果目标网站使用了CDN,使用了cdn真实的ip会被隐藏,如果要查找真实的服务器就必须获取真实的ip,根据这个ip继续查询旁站。 注意:很多时候,主站虽…

【信息收集】收集子域名

一、子域名作用二、常用方式三、域名的类型3.1 A (Address) 记录3.2 别名(CNAME)记录3.3 如何检测CNAME记录?3.4 MX(Mail Exchanger)记录3.5 什么是TXT记录?3.6 什么是NS记录?3.7 子域名在线查询13.8 子域名在线查询23.9 dns侦测3.10 IP138查询子域名3…

船新的神仙语录

重新开坑!开坑原因:最近看到的乐子有点多,现在没有只有周末能更新的问题了,所以重新开坑!欢迎投稿! begin:2024.8.30 2024秋QwQwQ

生物信息学家、计算机科学家和遗传学家,谁主导开发的生物信息学工具更好?

新西兰奥塔哥大学高级讲师(Senior Lecturer ) Paul P. Gardner 在 bioRxiv 上发表了一篇名为《A Bioinformatician, Computer Scientist, and Geneticist lead bioinformatic tool development — which one is better?》的预印版文章,旨在探讨生物信息学软件工具开发中,作…

[WPF]数据绑定时为何会出现StringFormat失效

在数据绑定过程中,我们经常会使用StringFormat对要显示的数据进行格式化,以便获得更为直观的展示效果,但在某些情况下格式化操作并未生效,例如 Button的 Content属性以及ToolTip属性绑定数据进行StringFormat时是无效的。首先回顾一下StringFormat的基本用法。 StringForma…

GDB调试器使用指南:设置断点、单步调试和查看寄存器状态

介绍了使用ddd进行C程序的调试过程,包括设置断点、单步调试、查看寄存器状态等操作。通过图示展示了相关操作步骤,帮助用户更好地理解调试工具的使用方法。使用 ​ddd ./eg​ 设置 ​​ 断点 ​​ 运行 ​​ 点击​run​​ 单步调试 ​Next​命令将执行到下一条指令。 这包括…