zcclxx / think-api-request-log
ThinkPHP 模块 API 请求日志:中间件采集 + RabbitMQ + 按月分表落库
Package info
gitee.com/zcclxx/thinkphp-mq.git
Type:composer-plugin
pkg:composer/zcclxx/think-api-request-log
Requires
- php: >=7.1.0
- composer-plugin-api: ^1.0 || ^2.0
- php-amqplib/php-amqplib: ^3.7
- topthink/framework: ^6.0|^8.0
Suggests
- workerman/workerman: 消费命令 timer 模式需要
This package is not auto-updated.
Last update: 2026-05-16 05:24:39 UTC
README
ThinkPHP 模块 API 请求日志:中间件采集请求 → RabbitMQ 异步入队 → 消费者按月分表落库;MQ 失败时自动兜底写库。
适用于 ThinkPHP 6 / 8 多应用项目,在 api 等模块 的 middleware.php 中按需挂载。
功能
- 记录 URL、方法、pathinfo、控制器/操作、IP、User-Agent、请求参数、请求头、HTTP 状态码、响应体
- 敏感参数与请求头自动脱敏(可配置)
- 响应体超长自动截断(默认 15000 字符)
- RabbitMQ 异步入队,降低接口耗时
- MQ 发布失败时同步写库兜底
- 按月自动建表:
{表前缀}api_request_log_YYYYMM - 控制台消费:
once(cron)/timer(Workerman 定时)
环境要求
- PHP >= 7.1.0(ThinkPHP 6 实际建议 7.2+,TP8 需 PHP 8.0+)
- ThinkPHP ^6.0 或 ^8.0
- php-amqplib/php-amqplib ^3.7
- MySQL(落库)
- RabbitMQ(
amqp.enable=true时) - Workerman(可选,仅
timer消费模式需要)
安装
1. Composer 引入
Packagist / 私有仓库:
composer require zcclxx/think-api-request-log
本地路径开发:
在业务项目 composer.json 增加:
{
"repositories": [
{
"type": "path",
"url": "../mq",
"options": { "symlink": true }
}
],
"require": {
"zcclxx/think-api-request-log": "^1.0"
},
"config": {
"allow-plugins": {
"zcclxx/think-api-request-log": true
}
}
}
然后执行(不要只写包名不带版本,path 仓库建议用 ^1.0 或 @dev):
composer update zcclxx/think-api-request-log
若曾安装旧包名 jg/mq-amqp,请先移除再装:
composer remove jg/mq-amqp
composer require zcclxx/think-api-request-log:^1.0
安装后 ThinkPHP 会通过 extra.think.services 自动加载 Zcclxx\ApiRequestLog\ServiceProvider,无需手动注册。
composer require / composer update 结束时,包内 Composer 插件 会交互式询问:
是否将 api-request-log 配置文件发布到 config/ 目录? [Y/n]
- 输入 Y 或直接回车:生成
config/amqp.php、config/api_request_log.php(仅复制尚不存在的文件) - 输入 n:跳过;包仍会使用内置默认配置,可稍后手动发布
- CI / 非交互(
composer install --no-interaction):自动跳过,不弹窗
未发布时功能照常可用(ServiceProvider 会合并包内默认配置);发布只是为了方便在项目中直接改连接信息。
发布稳定版(解决 minimum-stability (stable) 无法安装)
业务项目默认 minimum-stability 为 stable,只有 Packagist 上存在带稳定标签的版本时,composer require zcclxx/think-api-request-log 才会成功。
方式一:发布到 Packagist(公开稳定版)
- 准备 Git 仓库(GitHub / Gitee / GitLab 等),将本包代码推送到默认分支(如
main/master)。 - 确认
composer.json中name为zcclxx/think-api-request-log,与 Packagist 上的 vendor/package 一致。 打 Git 标签(稳定版必须以 v 前缀 的语义化版本为准,不要用仅靠
composer.json里的"version"代替):git tag -a v1.0.0 -m "Release 1.0.0" git push origin v1.0.0打开 Packagist → Submit → 填入仓库地址 → 提交。首次会抓取默认分支;打上
v1.0.0标签后,Packagist 会出现 1.0.0 稳定版。在业务项目中安装:
composer require zcclxx/think-api-request-log:^1.0
说明: 若包已上架 Packagist,建议从 composer.json 中删除 "version": "1.0.0" 字段,版本以 Git 标签 为准(Packagist 会提示);本地 path 开发可临时保留 version 方便解析。
方式二:不发布 Packagist,用私有 Git 源
在业务项目 composer.json 中声明 VCS,并同样打 v1.0.0 标签后推送:
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/你的账号/think-api-request-log.git"
}
],
"require": {
"zcclxx/think-api-request-log": "^1.0"
},
"config": {
"allow-plugins": {
"zcclxx/think-api-request-log": true
}
}
}
方式三:仅本地 path(不追求 stable 名)
"repositories": [{ "type": "path", "url": "../mq" }],
"require": { "zcclxx/think-api-request-log": "^1.0" }
若未打 Git 标签、仅靠 path,可能被识别为 dev,此时业务项目需:
composer require zcclxx/think-api-request-log:@dev
或把根项目 composer.json 设为 "minimum-stability": "dev", "prefer-stable": true(不推荐全局改,优先打 v1.0.0)。
2. 配置文件(可选发布)
方式 A:安装时按提示发布(推荐)
安装包时根据上述提示选择 Y 即可。
方式 B:手动发布
php think vendor:publish
若 config/amqp.php 或 config/api_request_log.php 已存在且要覆盖,使用:
php think vendor:publish -f
会在项目 config/ 下生成:
config/amqp.php— RabbitMQ 连接(按环境修改)config/api_request_log.php— 中间件脱敏、用户 ID 等(可选)
也可手动从包内复制:vendor/zcclxx/think-api-request-log/config/amqp.php → config/amqp.php。
config/amqp.php 默认内容示例(请改为你的 RabbitMQ 信息):
<?php
return [
// 是否走 RabbitMQ;false 时中间件直接写库
'enable' => (bool) env('amqp.enable', true),
'host' => env('amqp.host', '127.0.0.1'),
'port' => (int) env('amqp.port', 5672),
'user' => env('amqp.user', 'guest'),
'password' => env('amqp.password', 'guest'),
'vhost' => env('amqp.vhost', '/'),
'heartbeat' => (int) env('amqp.heartbeat', 30),
'connect_timeout' => (float) env('amqp.connect_timeout', 3.0),
'read_write_timeout' => (float) env('amqp.read_write_timeout', 0),
'api_request_log' => [
// 队列名须与 RabbitMQ 管理界面、消费者一致
'queue' => env('amqp.queue.api_request_log', 'api_request_log'),
],
];
3. 环境变量(.env,推荐)
# RabbitMQ
amqp.enable = true
amqp.host = 127.0.0.1
amqp.port = 5672
amqp.user = guest
amqp.password = guest
amqp.vhost = /
amqp.heartbeat = 30
amqp.connect_timeout = 3.0
amqp.read_write_timeout = 0
amqp.queue.api_request_log = api_request_log
本地无 MQ 时可设 amqp.enable = false,中间件会直接写库,便于调试。
4. 中间件配置(可选)
在业务项目 config/api_request_log.php 中可覆盖脱敏规则、用户 ID 解析等。包启动时会与内置配置做 array_replace_recursive 合并。
user_id_resolver 说明:日志里的 user_id 只来自本闭包,或(未配置有效 callable 时)tinywan\JWT::getCurrentId();不会自动使用请求参数里的 user_id。须传入 callable,不能写字符串 "user_id"。从请求头取值时注意:请求头可被伪造,适合网关已鉴权并下发可信头的场景;对外 API 更稳妥的是 Session、或解析你们自己的 Token 后再返回用户主键。
示例:
<?php
return [
// 方式 A:网关注入的用户 ID(请求头名大小写不敏感)
'user_id_resolver' => function (\think\Request $request) {
return (int) ($request->header('X-User-Id', 0));
},
// 方式 B:Session(键名按项目修改;与方式 A 二选一即可)
// 'user_id_resolver' => function (\think\Request $request) {
// return (int) ($request->session('uid') ?? 0);
// },
// 方式 C:业务里挂在 Request 上的属性(需由前置中间件赋值)
// 'user_id_resolver' => function (\think\Request $request) {
// return (int) ($request->userId ?? 0);
// },
'middleware' => [
'response_max_chars' => 15000,
'sensitive_params' => ['password', 'token'],
'sensitive_headers' => ['authorization', 'cookie'],
],
];
队列名、MQ 连接请在 config/amqp.php 或 .env 中配置,不要写在 api_request_log.php 里。
在模块中启用中间件
多应用下,在需要记录日志的模块 middleware.php 中加入:
<?php
use Zcclxx\ApiRequestLog\Middleware\ApiRequestLog;
return [
ApiRequestLog::class,
];
也可使用 ServiceProvider 注册的别名:
return [
'api_request_log',
];
示例路径:
| 作用范围 | 文件 |
|---|---|
| api 模块 | app/api/middleware.php |
| shop 模块 | app/shop/middleware.php |
| admin 模块 | app/admin/middleware.php |
| 全局 | app/middleware.php |
模块名不必叫 api,在任意多应用模块的 middleware.php 加上中间件即可。日志会自动写入 module 字段(如 shop、admin),便于按模块筛选:
SELECT * FROM api_request_log_202605 WHERE module = 'shop';
自定义模块名(可选):
// config/api_request_log.php
'module_resolver' => function (\think\Request $request) {
return (string) $request->app(); // 或你自己的逻辑
},
单路由(示例):
Route::group('api', function () {
// ...
})->middleware(\Zcclxx\ApiRequestLog\Middleware\ApiRequestLog::class);
数据流
HTTP 请求
→ ApiRequestLog 中间件(采集、脱敏)
→ amqp.enable = true → RabbitMQ 队列
→ amqp.enable = false → 直接写库
→ MQ 发布失败 → 兜底写库
php think api-request-log:consume
→ 从队列拉取 → 写入 api_request_log_YYYYMM
消费队列
安装包后自动注册命令 api-request-log:consume。
once:拉一批后退出(适合 cron)
# 默认每轮最多 500 条
php think api-request-log:consume once
# 自定义条数,0 表示直到队列为空
php think api-request-log:consume once -l 500
cron 示例(每分钟):
* * * * * cd /path/to/project && php think api-request-log:consume once -l 500 >> /dev/null 2>&1
timer:Workerman 定时消费
需先安装 workerman/workerman。
# 前台,每 30 秒一批
php think api-request-log:consume timer -i 30 -l 500
# 守护进程
php think api-request-log:consume timer -d -i 30 -l 500
# 停止(Linux)
php think api-request-log:consume timer-stop
PID 与日志文件位于项目 runtime/:
api_request_log_timer.pidworkerman_api_request_log_timer.log
数据表
表名:{database.connections.mysql.prefix}api_request_log_YYYYMM
首次写入当月数据时自动建表;旧表会自动补全 module、http_status、response_content、request_headers 等字段。
主要字段:
| 字段 | 说明 |
|---|---|
| user_id | 用户 ID,解析失败为 0 |
| module | ThinkPHP 多应用名称(如 api、shop、admin) |
| url / method / pathinfo | 请求地址信息 |
| controller / action | 控制器与操作 |
| ip / useragent | 客户端信息 |
| params | 请求参数 JSON(敏感字段已脱敏) |
| request_headers | 请求头 JSON(敏感头已脱敏) |
| http_status | HTTP 状态码 |
| response_content | 响应体(过长会截断) |
| create_time | 记录时间戳 |
配置项说明
config/amqp.php(config('amqp.xxx'))
| 键 | 说明 | 默认 |
|---|---|---|
enable | 是否走 MQ | true |
host / port / user / password / vhost | RabbitMQ 连接 | 见 config/amqp.php / .env |
heartbeat | 心跳秒数 | 30 |
connect_timeout | 连接超时(秒) | 3.0 |
read_write_timeout | 读写超时(秒),0 表示 max(6, heartbeat*2) | 0 |
api_request_log.queue | 队列名(生产与消费须一致) | api_request_log |
config/api_request_log.php(config('api_request_log.xxx'))
| 键 | 说明 | 默认 |
|---|---|---|
user_id_resolver | callable(Request): mixed(转 int),日志字段 user_id;非 callable 则走 JWT 或 0;与请求参数 user_id 无自动关联 | null(见上文示例与安全说明) |
module_resolver | callable(Request): string,自定义模块名 | null(自动读当前应用名) |
middleware.response_max_chars | 响应体最大入库字符数 | 15000 |
middleware.sensitive_params | 敏感参数字段名 | 见包内默认配置 |
middleware.sensitive_headers | 敏感请求头名 | 见包内默认配置 |
目录结构
mq/
├── composer.json
├── config/
│ ├── amqp.php # RabbitMQ 默认配置(安装后发布到项目)
│ └── api_request_log.php # 中间件默认配置
├── src/
│ ├── ServiceProvider.php # ThinkPHP 服务注册
│ ├── Middleware/
│ │ └── ApiRequestLog.php # 中间件
│ ├── Publisher/
│ │ └── AmqpPublisher.php # MQ 发布
│ ├── Storage/
│ │ └── DatabaseStorage.php # 按月分表写库
│ ├── Amqp/
│ │ └── SimplePublisher.php # AMQP JSON 发布
│ └── Command/
│ └── ApiRequestLogConsume.php
└── README.md
常见问题
Q:中间件加了但没有日志?
- 确认请求确实经过该模块中间件
- 检查
amqp.enable:为true时需启动消费者;为false时直接查当月分表 - 查看 ThinkPHP 日志中
[api_request]相关错误
Q:队列有消息但库中没有?
- 执行
php think api-request-log:consume once手动消费 - 核对
config/amqp.php中api_request_log.queue与 RabbitMQ 管理界面中的队列名、vhost 是否一致
Q:如何获取 JWT 用户 ID?
安装 tinywan/jwt 且未配置 user_id_resolver 时会尝试 getCurrentId();否则请在 config/api_request_log.php 中配置闭包(见包内 config/api_request_log.php 注释与上文示例)。
Q:安装后必须手动 vendor:publish 吗?
不必。安装/更新时会交互式询问是否发布;不发布也能用(走包内默认配置 + .env)。非交互环境需手动执行 php think vendor:publish;若 config/ 下已有同名文件需覆盖,加 -f。
Q:安装后必须有哪些配置?
config/amqp.php:建议发布并填写 RabbitMQ 连接(安装时选 Y,或vendor:publish)config/api_request_log.php:可选,用于脱敏与用户 ID
Q:minimum-stability (stable) 找不到版本?
包未在 Packagist 上架、或仓库没有打 v1.0.0 这类稳定标签时会出现。请按上文「发布稳定版」打标签并提交 Packagist,或改用 VCS/path + 明确版本约束。临时可:composer require zcclxx/think-api-request-log:@dev(不推荐生产)。
Q:composer require 报 consistency issue / 找不到包?
常见原因与处理:
- path 仓库包缺少版本:本包已声明
"version": "1.0.0",请用^1.0或@dev,不要裸写composer require zcclxx/think-api-request-log - 业务项目
repositories未配置 path:url指向本包目录,如"../mq" - 仍引用旧包名
jg/mq-amqp:先composer remove jg/mq-amqp再装新包 - Composer 插件未放行:在业务项目
composer.json加"allow-plugins": { "zcclxx/think-api-request-log": true } - 修改后执行:
composer clear-cache && composer update zcclxx/think-api-request-log -W
Q:从旧版迁移?
继续使用 config/amqp.php 即可,队列名为 api_request_log.queue(或 .env 的 amqp.queue.api_request_log)。
License
MIT