feat(stack): 所有 Docker 模式集成 XHProf 性能分析

在 docker-dev/docker-dev-sync/docker-serve/full 四个模式中集成 XHProf
性能分析能力,默认不启用(--profile xhprof 按需开启),零侵入不改
业务代码和 run.sh。

核心组件:
- source/docker/xhprof-bootstrap.php: 采集器初始化(auto_prepend_file)
- source/docker/xhgui-config.php: XHGui 认证配置(Basic Auth)+ PDO 存储
- 各 Dockerfile: 安装 PECL xhprof 扩展 + php-profiler 到 /opt/xhprof/
- 各 docker-compose: 新增 xhgui 服务(profiles: xhprof),端口 8142

存储方案:PDO MySQL(复用现有 MySQL),避免 MongoDB PHP 驱动兼容性问题。
docker-dev/docker-dev-sync 开箱即用;docker-serve/full 需配置 XHGUI_PDO_DSN。

认证:HTTP Basic Auth,默认 admin/xhgui123,环境变量可覆盖。
采集控制:XHPROF_ENABLE 环境变量 + cookie _profiler 强制触发 + 1% 采样。
Dockerfile.base 同步新增 xhprof 扩展(框架作者需重建推送基础镜像)。
This commit is contained in:
augushong
2026-08-09 09:07:10 +08:00
parent af0988118a
commit e0e2580646
12 changed files with 319 additions and 4 deletions

View File

@@ -0,0 +1,58 @@
<?php
/**
* XHGui 配置
*
* 通过 docker compose volume 挂载到 XHGui 容器的 config/config.php。
*
* 存储后端PDOMySQL避免 MongoDB PHP 驱动版本兼容性问题。
* 认证HTTP Basic Auth。
*
* 环境变量控制:
* - XHGUI_AUTH_USER 认证用户名(空=不启用认证,向后兼容)
* - XHGUI_AUTH_PASS 认证密码
* - XHGUI_PDO_DSN PDO DSN默认用 docker-dev 的 MySQL
* - XHGUI_PDO_USER 数据库用户名
* - XHGUI_PDO_PASS 数据库密码
* - XHGUI_PDO_TABLE 数据表名(默认 xhgui_results
*/
// PDO 存储配置(复用 docker-dev 的 MySQLXHGUI_PDO_INITSCHEMA=true 自动建表)
$pdoDsn = getenv('XHGUI_PDO_DSN') ?: 'mysql:host=mysql;dbname=ulthon;charset=utf8mb4';
return [
// 使用 PDO 存储替代 MongoDB避免 MongoDB PHP 驱动 2.x 兼容性问题)
'save.handler' => 'pdo',
'pdo' => [
'dsn' => $pdoDsn,
'user' => getenv('XHGUI_PDO_USER') ?: 'root',
'pass' => getenv('XHGUI_PDO_PASS') ?: 'root',
'table' => getenv('XHGUI_PDO_TABLE') ?: 'xhgui_results',
'tableWatch' => getenv('XHGUI_PDO_TABLE_WATCHES') ?: 'xhgui_watches',
'initSchema' => getenv('XHGUI_PDO_INITSCHEMA') ?: 'true',
],
'authentication' => function () {
$user = getenv('XHGUI_AUTH_USER');
$pass = getenv('XHGUI_AUTH_PASS');
// 未配置认证则直接放行(兼容内网/开发环境不设密码的场景)
if (empty($user)) {
return true;
}
// 验证 HTTP Basic Authhash_equals 防止时序攻击)
$sentUser = $_SERVER['PHP_AUTH_USER'] ?? '';
$sentPass = $_SERVER['PHP_AUTH_PW'] ?? '';
if (hash_equals($user, $sentUser) && hash_equals($pass, $sentPass)) {
return true;
}
// 认证失败,发送 401 响应
header('WWW-Authenticate: Basic realm="XHGui Performance Analyzer"');
http_response_code(401);
echo 'Authentication required.';
return false;
},
];

View File

@@ -0,0 +1,66 @@
<?php
/**
* XHProf 性能分析采集器初始化脚本
*
* 通过 PHP auto_prepend_file 机制自动加载,零侵入业务代码。
* 采集数据通过 HTTP Upload 发送到 XHGui 可视化服务。
*
* 环境变量控制:
* - XHPROF_ENABLE=true 开启采集(默认关闭)
* - XHGUI_UPLOAD_URL XHGui 上传地址(默认 http://xhgui:80/run/import
* - XHGUI_UPLOAD_TOKEN 上传令牌(默认 ulthon-admin-xhprof
*
* Cookie 手动触发:
* - 浏览器请求带 cookie _profiler=1 时强制采集(忽略采样率)
*/
// 1. 环境变量开关检查(默认关闭)
if (getenv('XHPROF_ENABLE') !== 'true') {
return;
}
// 2. 优雅降级php-profiler 未安装时静默退出,不报错不影响应用
if (!is_file('/opt/xhprof/vendor/autoload.php')) {
return;
}
// 3. 加载 php-profiler autoloader
require_once '/opt/xhprof/vendor/autoload.php';
use Xhgui\Profiler\Profiler;
use Xhgui\Profiler\ProfilingFlags;
// 4. 配置 Profiler
$config = [
// 采集标志CPU + 内存 + 不记录内置函数 + 不记录 span
'profiler.flags' => [
ProfilingFlags::CPU,
ProfilingFlags::MEMORY,
ProfilingFlags::NO_BUILTINS,
ProfilingFlags::NO_SPANS,
],
// 数据上传方式HTTP POST 到 XHGui
'save.handler' => Profiler::SAVER_UPLOAD,
'save.handler.upload' => [
'url' => getenv('XHGUI_UPLOAD_URL') ?: 'http://xhgui:80/run/import',
'timeout' => 3,
'token' => getenv('XHGUI_UPLOAD_TOKEN') ?: 'ulthon-admin-xhprof',
],
// 采集控制cookie 强制触发 或 1% 随机采样
'profiler.enable' => function () {
// 浏览器带 cookie _profiler 时强制采集(手动调试)
if (!empty($_COOKIE['_profiler'])) {
return true;
}
// 默认 1% 采样率
return mt_rand(1, 100) === 1;
},
];
// 5. 启动采集(异常不影响应用正常运行)
try {
$profiler = new Profiler($config);
$profiler->start();
} catch (\Throwable $e) {
error_log('[xhprof] ' . $e->getMessage());
}