[ ProfilingFlags::CPU, ProfilingFlags::MEMORY, ProfilingFlags::NO_BUILTINS, ProfilingFlags::NO_SPANS, ], // 采集控制:cookie 强制触发 或 1% 随机采样 'profiler.enable' => function () { // 浏览器带 cookie _profiler 时强制采集(手动调试) if (!empty($_COOKIE['_profiler'])) { return true; } // 默认 1% 采样率 return mt_rand(1, 100) === 1; }, // URL 规范化:采集时原生计算 simple_url 写入 meta(path 去 query、纯数字段替换 :id)。 // 后台导入任务直接读 meta.simple_url,仅缺失时兜底计算,此为唯一实现点 'profiler.simple_url' => function ($url) { $path = parse_url($url, PHP_URL_PATH); $parts = explode('/', trim($path, '/')); foreach ($parts as &$p) { if ($p !== '' && ctype_digit($p)) { $p = ':id'; } } return implode('/', $parts); }, ]; // 7. 落盘方式分派(未知值回退 file) if ($saver === Profiler::SAVER_UPLOAD) { // upload:HTTP POST 到 XHGui(旧行为,兼容保留) $config['save.handler'] = Profiler::SAVER_UPLOAD; } elseif ($saver === Profiler::SAVER_STACK) { // stack:file + upload 双写(SaverFactory 递归创建 savers 数组中的每个 saver) $config['save.handler'] = Profiler::SAVER_STACK; $config['save.handler.stack'] = [ 'savers' => [Profiler::SAVER_FILE, Profiler::SAVER_UPLOAD], ]; } else { // file:本地 jsonl 文件落盘(默认) $config['save.handler'] = Profiler::SAVER_FILE; } // FileSaver 不自建目录,start 前确保目录存在 if ($saver !== Profiler::SAVER_UPLOAD) { @mkdir($fileDir, 0777, true); } // 按天分文件(runs-{Ymd}.jsonl):filename 在每个请求求值(bootstrap 每请求执行), // date() 跨天自然滚动;导入任务可安全删除已导完的整天文件 $config['save.handler.file'] = [ 'filename' => $fileDir . '/runs-' . date('Ymd') . '.jsonl', ]; $config['save.handler.upload'] = [ 'url' => getenv('XHGUI_UPLOAD_URL') ?: 'http://xhgui:80/run/import', 'timeout' => 3, 'token' => getenv('XHGUI_UPLOAD_TOKEN') ?: 'ulthon-admin-xhprof', ]; // 8. 启动采集(异常不影响应用正常运行) try { $profiler = new Profiler($config); $profiler->start(); } catch (\Throwable $e) { error_log('[xhprof] ' . $e->getMessage()); }