需先在中间件中将请求日志写入数据库,再通过自定义命令行指令(如statrequestdaily)查询昨日数据并汇总;表结构应含url、controller、action、status、runtime、create_time等字段,查询时用db::raw()提升性能。

定时任务里怎么获取 ThinkPHP 的请求日志数据
ThinkPHP 本身不自带请求统计日志,得先确认你是否已开启行为日志或自定义中间件记录了请求信息。没存数据,定时任务就无从汇总——常见错误是直接写定时脚本去查 access_log 文件或 Nginx 日志,但那和 TP 的路由、控制器、响应码等上下文脱节。
推荐做法:在 app/middleware/LogRequest.php 中记录关键字段到数据库(如 request_log 表),包含 url、controller、action、status、runtime、create_time。确保该中间件已注册到全局中间件队列。
- 表结构至少含
id、url(VARCHAR 255)、controller(VARCHAR 100)、action(VARCHAR 100)、status(TINYINT)、runtime(DECIMAL(6,3))、create_time(INT) - 避免记录 POST body 或大字段,否则写入慢、磁盘涨得快
- 用
date('Y-m-d H:i:s')而非time()存时间,方便后续 SQL 按日期分组
用 think:command 创建可调度的统计命令
别手写 shell 脚本调 php index.php,TP 自带命令行支持更可控。执行 php think make:command StatRequestDaily 生成命令类,然后在 app/command/StatRequestDaily.php 中编写逻辑。
核心是查昨天的数据并写入汇总表(比如 stat_request_daily),注意用 Db::raw() 避免 ORM 性能损耗:
$yesterday = date('Y-m-d', strtotime('-1 day'));
Db::name('request_log')
->where('create_time', '>=', strtotime($yesterday))
->where('create_time', 'field('controller, action, count(*) as cnt, avg(runtime) as avg_runtime, sum(if(status=200,1,0)) as success_cnt')
->group('controller, action')
->select();
- WHERE 条件必须用时间戳范围,不能用
DATE(FROM_UNIXTIME(create_time)) = ?,否则无法走索引 - 汇总表建议加联合索引:
(stat_date, controller, action) - 如果日志量大(单日 >10 万),考虑用
chunk分批处理,避免内存溢出
Crontab 调用时要注意 PATH 和当前目录
Linux 定时任务默认 PATH 很窄,且工作目录不是项目根目录,直接写 php think stat:request:daily 会报错“command not found”或“Cannot find app/”。
正确写法(加入 crontab):
0 2 * * * cd /var/www/mytp && /usr/bin/php think stat:request:daily >> /var/log/tp-stat.log 2>&1
- 务必用绝对路径调用
php,查路径用which php -
cd /var/www/mytp确保加载正确的think入口和配置 - 重定向日志便于排查,比如
Class 'app\command\StatRequestDaily' not found就是自动加载失败,多半是命名空间或文件名大小写不对
统计结果怎么安全导出或对接看板
别让定时任务直接 echo 或 print_r 到终端——crontab 不认这些输出,也难对接 Grafana 或 BI 工具。应该把结果存库或写 JSON 文件。
例如写入 /runtime/stat/daily_20240520.json:
$data = ['date' => $yesterday, 'items' => $result];
file_put_contents(RUNTIME_PATH . 'stat/daily_' . str_replace('-', '', $yesterday) . '.json', json_encode($data, JSON_UNESCAPED_UNICODE));
- JSON 文件要加权限控制(
chmod 644),别放 web 可访问目录下 - 如果需实时查询,建议加个简单 API 接口(如
GET /api/v1/stat/daily?date=2024-05-20),用Db::name('stat_request_daily')查,别读文件 - 敏感指标(如错误率突增)可在此处加钉钉/企微 Webhook,但别在循环里发,聚合后只发一次
真正麻烦的是数据一致性:如果定时任务执行中,新的请求还在写 request_log,得用 WHERE 时间范围+事务隔离,或者干脆把统计窗口设为“前天”,留出缓冲。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











