mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-08-30 04:35:33 +08:00
docs(stack): XHProf 后台化验证报告
This commit is contained in:
116
source/docs/xhprof-backend-verification-report.html
Normal file
116
source/docs/xhprof-backend-verification-report.html
Normal file
@@ -0,0 +1,116 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>XHProf 后台化验证报告(Task 9 全链路验证与存证)</title>
|
||||
<style>
|
||||
body { font-family: "Microsoft YaHei", "Segoe UI", sans-serif; margin: 24px auto; max-width: 1100px; color: #333; line-height: 1.6; }
|
||||
h1 { font-size: 22px; border-bottom: 2px solid #16baaa; padding-bottom: 8px; }
|
||||
h2 { font-size: 17px; margin-top: 28px; color: #16a;
|
||||
border-left: 4px solid #16baaa; padding-left: 10px; }
|
||||
table { border-collapse: collapse; width: 100%; margin: 10px 0; font-size: 13px; }
|
||||
th, td { border: 1px solid #ddd; padding: 6px 10px; text-align: left; vertical-align: top; }
|
||||
th { background: #f2fafa; }
|
||||
.pass { color: #0a9463; font-weight: bold; }
|
||||
.fail { color: #d43f3f; font-weight: bold; }
|
||||
.warn { color: #c47b00; font-weight: bold; }
|
||||
code, pre { font-family: Consolas, monospace; background: #f6f6f6; font-size: 12px; }
|
||||
pre { padding: 10px; overflow-x: auto; border: 1px solid #e5e5e5; }
|
||||
.shots img { max-width: 100%; border: 1px solid #ccc; margin: 6px 0; display: block; }
|
||||
.shots figcaption { font-size: 12px; color: #666; margin-bottom: 14px; }
|
||||
.meta { color: #666; font-size: 13px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>XHProf 后台化验证报告</h1>
|
||||
<p class="meta">计划:.omo/plans/xhprof-log-backend.md Task 9(Wave 5 终验)<br>
|
||||
环境:docker-dev 栈(Windows 宿主 + docker compose,ulthon_admin:8000 / mysql:13306)<br>
|
||||
执行时间:2026-08-14 23:30 ~ 2026-08-15 10:45(Asia/Shanghai)<br>
|
||||
执行身份:Sisyphus-Junior(验证 + 一处 T7 缺陷修复)</p>
|
||||
|
||||
<h2>一、主链断言(6 组,全部通过)</h2>
|
||||
<table>
|
||||
<tr><th>#</th><th>断言</th><th>实测结果</th><th>判定</th></tr>
|
||||
<tr><td>1</td><td>XHPROF_ENABLE=true 重启栈(无 profile)无 xhgui 容器</td><td>compose ps 仅 4 服务(mysql/redis/phpmyadmin/ulthon_admin);docker ps -a 无 xhgui/xhprof 容器;容器内 env XHPROF_ENABLE=true。注:旧 xhgui 残留容器需带 --profile xhgui down 才会移除(compose down 不动非激活 profile 的容器,符合预期语义)</td><td class="pass">PASS</td></tr>
|
||||
<tr><td>2</td><td>5 次 _profiler=1 请求(curl -b)当天 jsonl 行数=5</td><td>5 请求全 200;runs-20260815.jsonl wc -l=5,5 行均含 "profile"+"meta" 键,末字节 \n(注:请求后立即 wc 曾见 4,系 fastcgi 响应先于 shutdown 落盘的毫秒级窗口,1 秒后补齐)</td><td class="pass">PASS</td></tr>
|
||||
<tr><td>3</td><td>导入后 run/detail 各 +5,导完 jsonl 删除</td><td>timer 自动轮(ul_system_timer_log id=755)抢先导入:{"files":1,"runs":5,"watches":10,"fails":0,"deleted":1};run 12→17(+5,node_id=d804e1bd9e6d-ac4562f2),detail 12→17(+5),xhprof 目录空(文件已删)</td><td class="pass">PASS</td></tr>
|
||||
<tr><td>4</td><td>watch 命中数 >0 且 SQL 执行层规则 wt_sum > 0</td><td>启用规则命中 26 条;watch_id=2(SQL 执行层,regex 实测 hex=7E7468696E6B5C5C64625C5C50444F436F6E6E656374696F6E3A3A2E2A7E 即 ~think\\db\\PDOConnection::.*~)12 命中 wt_sum=5554063us;watch_id=3 业务层控制器 2 命中;watch_id=4 数据保存 12 命中</td><td class="pass">PASS</td></tr>
|
||||
<tr><td>5</td><td>四页面 200:列表无添加钮 / 详情含 main() / watch 3 条 / 命中记录</td><td>xhprof.run/index 200 code=0(视图 toolbar:[],data-auth 仅 index/detail);detail?id=20 200 响应含 "fn": "main()";xhprof.watch/index 200 count=3;xhprof.run_watch/index 200 count=33</td><td class="pass">PASS</td></tr>
|
||||
<tr><td>6</td><td>清理:dry-run 统计 → 真跑 → 过期=0 未过期不动;xhgui_results 不变(Must-NOT)</td><td>造 31 天前种子(id 900001/900002 含 detail+run_watch);dry-run {"run_watch_deleted":2,"detail_deleted":2,"run_deleted":2,"dry_run":true};真跑同计数 dry_run:false;过期行全 0;未过期 17 条原样;xhgui_results 全程恒 27</td><td class="pass">PASS</td></tr>
|
||||
</table>
|
||||
|
||||
<h2>二、失败路径(4 条,全部通过)</h2>
|
||||
<table>
|
||||
<tr><th>#</th><th>场景</th><th>实测结果</th><th>判定</th></tr>
|
||||
<tr><td>F1</td><td>坏 JSON 行导入</td><td>追加非 JSON 文本行 → 导入 {"runs":1,"watches":2,"fails":1}:好行入库、坏行 fails+1 不中断</td><td class="pass">PASS</td></tr>
|
||||
<tr><td>F2</td><td>无换行半行</td><td>追加无换行半行 → 导入 runs=0(不入库);补齐剩余片段+换行 → 导入 runs=1,run 900005 wall_time=4321 与合成值精确一致;文件导完删除</td><td class="pass">PASS</td></tr>
|
||||
<tr><td>F3</td><td>非法正则被拒</td><td>POST add 提交无定界符 think\db → {"code":500,"msg":"正则非法(必须带定界符...)"};DB 无 T9-invalid 行</td><td class="pass">PASS</td></tr>
|
||||
<tr><td>F4</td><td>禁用规则不物化</td><td>建 status=0 合法规则 T9-disabled-probe → 采集+导入(runs=2 watches=4 均来自启用规则)→ 该规则 run_watch 0 行;对照组启用规则各 +2 命中。验证后已删探针规则</td><td class="pass">PASS</td></tr>
|
||||
</table>
|
||||
|
||||
<h2>三、回归(3 条 + 终态恢复,全部通过)</h2>
|
||||
<table>
|
||||
<tr><th>#</th><th>场景</th><th>实测结果</th><th>判定</th></tr>
|
||||
<tr><td>R1</td><td>XHPROF_ENABLE=false 静默</td><td>shell env 传 false 重建容器(env 确认)→ 5 次普通请求 + 3 次 _profiler=1 cookie 强制请求全 200,jsonl 目录无文件(总闸拦截 cookie 强制)</td><td class="pass">PASS</td></tr>
|
||||
<tr><td>R2</td><td>无 xhprof 报错</td><td>ul_debug_log 近期 error 级 0 条(含 xhprof 关键字 0 条);tools:log:show 尾部仅常规 SQL 日志</td><td class="pass">PASS</td></tr>
|
||||
<tr><td>R3</td><td>4 stack compose config</td><td>docker-dev / docker-dev-sync / docker-serve / full 四个 docker-compose.yaml config -q 全部 OK</td><td class="pass">PASS</td></tr>
|
||||
<tr><td>R4</td><td>终态恢复</td><td>XHPROF_ENABLE=true 重建容器 → _profiler=1 请求 → jsonl 1 行 → 手动导入 runs=1 watches=2 文件删除,采集闭环恢复;.env 无临时改动(全程 shell 环境变量传值)</td><td class="pass">PASS</td></tr>
|
||||
</table>
|
||||
|
||||
<h2>四、页面 QA(ulthon-page-qa checklist,两分辨率)</h2>
|
||||
<table>
|
||||
<tr><th>检查项</th><th>采样列表</th><th>运行详情</th></tr>
|
||||
<tr><td>页面可开(HTML)</td><td class="pass">OK(iframe 200)</td><td class="pass">OK(iframe 200)</td></tr>
|
||||
<tr><td>数据正确</td><td class="pass">表头 8 列齐全(请求时间/方法/URL/节点/总耗时/CPU耗时/内存峰值/操作),共 23 条</td><td class="pass">头部统计渲染(总耗时/CPU/SQL占比/内存峰值/请求信息)</td></tr>
|
||||
<tr><td>按钮显隐(data-auth)</td><td class="pass">toolbar 0 按钮(无添加,符合只读设计);操作列仅"详情"(data-auth-index/detail,index.html 无 add 标记)</td><td class="pass">无多余按钮</td></tr>
|
||||
<tr><td>搜索</td><td class="pass">搜索区由 cols 生成(request_time range / method 等)</td><td>-(详情页无搜索)</td></tr>
|
||||
<tr><td>1920x1080 布局</td><td class="pass">正常,操作列 fixed right</td><td class="pass">正常(弹层全屏)</td></tr>
|
||||
<tr><td>390x844 布局</td><td class="pass">不崩:表格横向滚动形态,数据行/分页/fixed 操作列完整(框架在此视口走横向滚动而非卡片)</td><td class="pass">不崩:头部统计纵向堆叠可读</td></tr>
|
||||
</table>
|
||||
<p>命中记录页(修复后):32 行可见,时间列 2026-08-15 08:23:49 格式正确,超阈值红色徽章(685.844 ms 超阈值 500ms)正常,console 0 errors。监控规则页:3 条预置规则 + regex 原文完整展示。</p>
|
||||
|
||||
<h2>五、验证中发现并处理的缺陷</h2>
|
||||
<table>
|
||||
<tr><th>#</th><th>缺陷</th><th>处置</th></tr>
|
||||
<tr><td>B1(已修复)</td><td>app/admin/view/xhprof/run_watch/index.js:26 调用 window.UA_CORE.util.toDateString —— UA_CORE 全项目零定义(T7 笔误 API),浏览器抛 "Cannot read properties of undefined (reading 'util')",命中记录页数据行渲染崩溃</td><td class="pass">照抄 T5 formatRequestTime 纯 JS 实现替换(保留 isNaN 兜底);实测 32 行正常渲染、console 0 error;fix 提交入库</td></tr>
|
||||
<tr><td>B2(已上报,不在 T9 修复范围)</td><td>app/admin/view/xhprof/run/detail.js:37 $.ajax 用裸相对 URL 'xhprof.run/detail',在 /admin/xhprof.run/detail iframe 内解析为 /admin/xhprof.run/xhprof.run/detail → 404,详情页函数表与 SQL 摘要在浏览器端加载失败(服务端渲染的头部统计正常;API 层功能本身正常)</td><td class="warn">上报编排器;建议修法 url: ua.url('xhprof.run/detail')(属 T6 文件,T9 红线禁止改动)</td></tr>
|
||||
</table>
|
||||
|
||||
<h2>六、关键命令与输出摘录</h2>
|
||||
<pre># 断言1:重启(PowerShell env 传值)
|
||||
$env:XHPROF_ENABLE='true'; docker compose -f source/stack/docker-dev/docker-compose.yaml up -d
|
||||
docker compose ps --format "{{.Name}} {{.Service}}" # 4 服务,无 xhgui
|
||||
|
||||
# 断言2:5 次强制采集(容器内)
|
||||
for i in 1 2 3 4 5; do curl -s -b "_profiler=1" -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/; done
|
||||
wc -l /var/www/html/runtime/xhprof/runs-20260815.jsonl # 5
|
||||
|
||||
# 断言3:timer 自动导入抢先(手动 /do 返回 files:0 因已被消费)
|
||||
SELECT result FROM ul_system_timer_log WHERE id=755;
|
||||
# {"files":1,"runs":5,"watches":10,"fails":0,"deleted":1,"errors":[]}
|
||||
|
||||
# 断言6:清理(防刷 query nonce;& 必须整体引号内,否则 PS/CRT 吃引号后 sh 将其后台化)
|
||||
curl -s -X POST "http://127.0.0.1:8000/tools/timer.XhprofRunClean/do?nonce=t9dryA&dryRun=1"
|
||||
# {"run_watch_deleted":2,"detail_deleted":2,"run_deleted":2,"dry_run":true}
|
||||
curl -s -X POST "http://127.0.0.1:8000/tools/timer.XhprofRunClean/do?nonce=t9realC"
|
||||
# {"run_watch_deleted":2,"detail_deleted":2,"run_deleted":2,"dry_run":false}
|
||||
|
||||
# 回归 R1:false 总闸(连 cookie 强制也拦)
|
||||
$env:XHPROF_ENABLE='false'; docker compose ... up -d # 8 请求全 200,jsonl 不生成</pre>
|
||||
|
||||
<h2>七、截图存证(6 张,1920x1080 + 390x844)</h2>
|
||||
<div class="shots">
|
||||
<figure><img src="../../runtime/agents/xhprof-backend-screenshots/01-run-index-1920.png" alt="采样列表 1920"><figcaption>01 采样列表(1920x1080,共 23 条,无添加按钮)</figcaption></figure>
|
||||
<figure><img src="../../runtime/agents/xhprof-backend-screenshots/02-run-detail-1920.png" alt="运行详情 1920"><figcaption>02 运行详情(1920x1080,头部统计正常;函数表受 B2 影响未加载,已上报)</figcaption></figure>
|
||||
<figure><img src="../../runtime/agents/xhprof-backend-screenshots/03-watch-index-1920.png" alt="监控规则 1920"><figcaption>03 监控规则(1920x1080,3 条预置规则)</figcaption></figure>
|
||||
<figure><img src="../../runtime/agents/xhprof-backend-screenshots/04-run-watch-index-1920.png" alt="命中记录 1920"><figcaption>04 命中记录(1920x1080,B1 修复后 32 行正常渲染 + 超阈值徽章)</figcaption></figure>
|
||||
<figure><img src="../../runtime/agents/xhprof-backend-screenshots/05-run-index-390.png" alt="采样列表 390"><figcaption>05 采样列表(390x844,横向滚动不崩)</figcaption></figure>
|
||||
<figure><img src="../../runtime/agents/xhprof-backend-screenshots/06-run-detail-390.png" alt="运行详情 390"><figcaption>06 运行详情(390x844,统计卡片纵向堆叠不崩)</figcaption></figure>
|
||||
</div>
|
||||
|
||||
<h2>八、结论</h2>
|
||||
<p>6 组主链断言 + 4 条失败路径 + 3 条回归(+终态恢复)全部通过;页面 QA 两分辨率不崩。XHProf 后台化全链路(采集 → jsonl 落盘 → 定时导入入库 → watch 物化 → 后台三页面 → 过期清理)在真实容器环境验证可用。遗留 B2(详情页浏览器端 ajax 相对路径 404)已上报编排器,不影响列表/命中/监控页面与服务端 API。</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user