zcclxx/think-api-request-log

ThinkPHP 模块 API 请求日志:中间件采集 + RabbitMQ + 按月分表落库

Maintainers

Package info

gitee.com/zcclxx/thinkphp-mq.git

Type:composer-plugin

pkg:composer/zcclxx/think-api-request-log

Statistics

Installs: 8

Dependents: 0

Suggesters: 0

1.0.4 2026-05-15 06:59 UTC

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.phpconfig/api_request_log.php(仅复制尚不存在的文件)
  • 输入 n:跳过;包仍会使用内置默认配置,可稍后手动发布
  • CI / 非交互composer install --no-interaction):自动跳过,不弹窗

未发布时功能照常可用(ServiceProvider 会合并包内默认配置);发布只是为了方便在项目中直接改连接信息。

发布稳定版(解决 minimum-stability (stable) 无法安装)

业务项目默认 minimum-stabilitystable,只有 Packagist 上存在带稳定标签的版本时,composer require zcclxx/think-api-request-log 才会成功。

方式一:发布到 Packagist(公开稳定版)

  1. 准备 Git 仓库(GitHub / Gitee / GitLab 等),将本包代码推送到默认分支(如 main / master)。
  2. 确认 composer.jsonname zcclxx/think-api-request-log,与 Packagist 上的 vendor/package 一致。
  3. 打 Git 标签(稳定版必须以 v 前缀 的语义化版本为准,不要用仅靠 composer.json 里的 "version" 代替):

    git tag -a v1.0.0 -m "Release 1.0.0"
    git push origin v1.0.0
    
  4. 打开 PackagistSubmit → 填入仓库地址 → 提交。首次会抓取默认分支;打上 v1.0.0 标签后,Packagist 会出现 1.0.0 稳定版。

  5. 在业务项目中安装:

    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.phpconfig/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.phpconfig/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 字段(如 shopadmin),便于按模块筛选:

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.pid
  • workerman_api_request_log_timer.log

数据表

表名:{database.connections.mysql.prefix}api_request_log_YYYYMM

首次写入当月数据时自动建表;旧表会自动补全 modulehttp_statusresponse_contentrequest_headers 等字段。

主要字段:

字段说明
user_id用户 ID,解析失败为 0
moduleThinkPHP 多应用名称(如 apishopadmin
url / method / pathinfo请求地址信息
controller / action控制器与操作
ip / useragent客户端信息
params请求参数 JSON(敏感字段已脱敏)
request_headers请求头 JSON(敏感头已脱敏)
http_statusHTTP 状态码
response_content响应体(过长会截断)
create_time记录时间戳

配置项说明

config/amqp.phpconfig('amqp.xxx')

说明默认
enable是否走 MQtrue
host / port / user / password / vhostRabbitMQ 连接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.phpconfig('api_request_log.xxx')

说明默认
user_id_resolvercallable(Request): mixed(转 int),日志字段 user_id;非 callable 则走 JWT 或 0;与请求参数 user_id 无自动关联null(见上文示例与安全说明)
module_resolvercallable(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.phpapi_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 / 找不到包?

常见原因与处理:

  1. path 仓库包缺少版本:本包已声明 "version": "1.0.0",请用 ^1.0@dev,不要裸写 composer require zcclxx/think-api-request-log
  2. 业务项目 repositories 未配置 pathurl 指向本包目录,如 "../mq"
  3. 仍引用旧包名 jg/mq-amqp:先 composer remove jg/mq-amqp 再装新包
  4. Composer 插件未放行:在业务项目 composer.json"allow-plugins": { "zcclxx/think-api-request-log": true }
  5. 修改后执行:composer clear-cache && composer update zcclxx/think-api-request-log -W

Q:从旧版迁移?

继续使用 config/amqp.php 即可,队列名为 api_request_log.queue(或 .envamqp.queue.api_request_log)。

License

MIT