日志需带标准时间戳和唯一接口路径,推荐全局中间件写json格式结构化日志;用awk+sort+uniq做轻量级日统计;定时任务分两步生成csv再原子导入;数据库查询须预拆路由层级避免like全表扫描。

日志格式必须带时间戳和接口路径
ThinkPHP 默认的 log 行为不记录完整请求 URL,只记级别、时间、消息体,没法直接按“每日 + 接口”聚合。得先改日志驱动或加中间件打点。
推荐在全局中间件里手动写结构化日志,比如用 file_put_contents 追加一行 JSON:
{"time":"2024-05-20 14:23:01","route":"api/v1/user/info","method":"GET"}
关键点:time 必须是标准格式(Y-m-d H:i:s),route 要能唯一标识接口(别用 Request::url(),含参数和域名,干扰统计)。
- 别依赖
Log::write()默认输出——它不保证顺序、不易 grep、字段不可控 - 避免把日志写进
runtime/log/下的 ThinkPHP 日志文件,会和框架日志混在一起,解析困难 - 如果用 Nginx 访问日志,确认
log_format包含$time_local和$request_uri,且没被反向代理头污染
用 awk + sort + uniq 做轻量级日统计
日志有了,每天跑一次脚本提取「日期 + 接口」组合并计数,比写 PHP 脚本更稳、更快、不占 PHP 进程。
假设日志路径是 /var/log/tp-api-access.log,每行是上面那种 JSON 格式:
awk -F'"' '/"time":"/ {print substr($4,1,10) " " $8}' /var/log/tp-api-access.log | sort | uniq -c | sort -nr
说明: 是 time 字段值,取前 10 位得日期; 是 route 字段值(JSON 字段顺序要固定);uniq -c 统计频次。
- 如果日志量大(单日 > 100 万行),加
LC_ALL=C加速sort:如LC_ALL=C sort - 别用
date -f解析时间再分组——太慢,字符串截取足够准 - 注意 JSON 字段顺序可能因 PHP 版本或序列化方式变化,建议统一用
json_decode($line, true)预处理成标准格式再入库,但临时分析用 awk 更快
定时任务别直接跑统计脚本到数据库
直接在 crontab 里用 php think command:import 导数据,容易卡住或失败后无感知。应该分两步:先生成统计结果文件,再原子化导入。
例如每天凌晨 2 点执行:
0 2 * * * cd /path/to/app && bash /path/to/stat/daily.sh >> /path/to/stat/cron.log 2>&1
其中 daily.sh 干三件事:1)用 awk 提取昨日数据;2)输出为 CSV;3)mv 到待处理目录。PHP 命令行任务只负责扫描该目录下的 CSV 文件,成功处理后 mv 到 done/。
- 避免 crontab 直接调 PHP——超时、内存溢出、异常退出都不好捕获
- 别用
file_get_contents读整个日志文件——大日志会 OOM,流式处理或交给 shell 工具 - 统计口径要对齐:比如 “每日” 指服务器本地时间 00:00–23:59,不是 UTC,也不是用户请求时间
查数据时别用 LIKE 匹配接口名
存进数据库后,查 “所有 /api/v1/user/* 的请求数”,很多人写 WHERE route LIKE '/api/v1/user/%',但 MySQL 对长文本字段走全表扫描,几千万行就卡死。
正确做法是预拆解路由层级,加一列 route_level1 存 api,route_level2 存 v1,route_level3 存 user,查询时用等值条件:
SELECT SUM(cnt) FROM daily_api_stat WHERE route_level1 = 'api' AND route_level2 = 'v1' AND route_level3 = 'user';
- 别在
route字段上建全文索引——精度低、开销大、不解决前缀模糊问题 - 如果接口路径带版本号(如
/v2/order/list),版本字段必须单独拆出来,否则 v1/v2 数据无法横向对比 - 注意 ThinkPHP 的路由可能重写(如
Route::get('u/:id', 'user/read')),日志里记的是实际匹配到的控制器方法,不是原始 URL,这点要和前端约定清楚
真正麻烦的不是统计本身,是日志源头是否稳定、字段是否可预测、时间是否对齐。一旦某个环节漂移(比如某天中间件挂了、Nginx 时间被改过、日志轮转没切好),后面所有数字都得重算。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











