thinkphp接口日志需在顶层中间件中统一记录结构化json日志,包含路径、方法、状态码、耗时、开始时间、ip、异常标识;耗时用microtime(true)首尾采集,状态码fallback至500,跳过options请求,避免敏感数据入日志;禁用trace()和拼接字符串日志,推荐导出至clickhouse/elasticsearch做qps与p95分析。

ThinkPHP 接口日志怎么打才可分析
默认的 Log::write() 或 trace() 打点不带结构化字段,没法直接进统计系统。要能算调用量、耗时分布、错误率,日志必须含统一字段:请求路径、方法、状态码、耗时(毫秒)、开始时间、IP、是否异常。
- 别用
Log::info("xxx")拼字符串——后续 grep 不可靠,JSON 解析失败率高 - 在中间件里统一拦截,用
thinkacadeLog::channel('api')->info()写 JSON 行日志(单行 JSON,不是格式化缩进) - 耗时必须用
microtime(true)在请求开始和结束时采集,别依赖框架内置的app_begin/app_end钩子——它们不覆盖所有异常退出路径 - 状态码优先取
$response->getCode(),fallback 到 500(比如未捕获异常导致响应为空时)
如何从日志提取调用量与 P95 耗时
日志文件本身只是文本,得靠外部工具聚合。ThinkPHP 不自带分析模块,硬写 PHP 脚本解析大日志容易 OOM,也难做分位数计算。
- 推荐用
awk+sort+head快速看趋势:awk -F'\|' '{print $4,$5}' runtime/log/api/*.log | sort -n | tail -n +$(wc -l ($4 是耗时,$5 是接口名,按需调整字段序号) - 真正生产环境建议导出到
clickhouse或elasticsearch,用group by route, status算 QPS,quantile(0.95)(cost_ms)算 P95 - 注意日志滚动策略:
MaxFiles设太小会导致旧日志被删,统计周期断层;设太大又影响grep效率
中间件里记录日志的典型漏点
很多同学在 AppInit 或 Http 类里加日志,结果发现 404、跨域预检、路由未匹配的请求全没记录——因为这些根本没走到控制器层。
- 必须把日志中间件注册在
app/middleware.php的最顶层(数组第一个),确保任何请求都经过 - 对
OPTIONS预检请求,手动跳过日志(否则日志量翻倍且无业务意义):if ($request->method() === 'OPTIONS') return $next($request); - 异常未被捕获时,
$response可能为null,要判空再取getCode(),否则报Call to a member function getCode() on null - 别在日志里记
$request->param()全量数据——含敏感字段、体积大、易被注入特殊字符破坏 JSON 结构
为什么不能直接用 ThinkPHP 自带的 trace 日志
trace() 是调试用的,输出格式随版本变,字段不固定,且默认关掉。开启后还会影响性能,尤其在并发高时写磁盘成瓶颈。
-
trace日志路径是runtime/log/trace/,和业务日志分离,没法和接口路径对齐 - 它不记录真实响应时间(只记到 dispatch 完),中间件、模板渲染、DB 查询后的耗时全漏了
- 开启
app_trace后,每个请求会额外生成一个 HTML 文件,上线环境必须关,否则磁盘爆满 - 如果真要用 trace,至少重写
thinklogdriverFile的save()方法,强制输出 JSON 格式,但不如从中间件重做干净
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










