ThinkPHP 6.1 多通道日志需明确定义各通道路径、正确设置 default 驱动、用 Log::think()->setChannel() 切换通道、通过中间件按路由自动分发、严格隔离 runtime 子目录权限。

ThinkPHP 6.1 支持多通道日志,但默认配置容易导致「看似切换了通道,实际仍写进 default.log」。关键不在“加几个 channel”,而在于初始化时机、实例缓存规避、路径隔离和中间件执行顺序。
日志通道必须独立配置,不能只改 config/log.php
config/log.php 中需明确定义多个通道(如 admin、api、swoole),每个通道的 path 必须指向不同目录,避免混写:
'channels' => [
'admin' => [
'type' => 'file',
'path' => runtime_path() . 'log/admin/',
'level' => 'error',
],
'api' => [
'type' => 'file',
'path' => runtime_path() . 'log/api/',
'level' => 'info',
],
'swoole' => [
'type' => 'file',
'path' => runtime_path() . 'log/swoole/',
'level' => 'debug',
],
],
'default' => 'file', // 注意:这里填驱动名,不是通道名
⚠️ 错误写法:'default' => 'admin' —— 这会让框架内部日志(如异常、SQL)全部走 admin 通道,失去控制。
中间件中切换通道,必须重置 Log 门面实例
Log 门面会缓存首次初始化的 logger 实例。仅调 Log::channel('admin') 不生效,必须用以下任一方式:
-
✅ 推荐(TP6.1+):
Log::think()->setChannel('admin'); -
✅ 更稳妥(兼容性更强):
$logger = Log::channel('admin'); $logger->info('管理员操作日志'); -
❌ 无效写法:
Log::channel('admin')->info('...'); // 门面未刷新,仍写 default.log
按请求路径或模块自动路由到对应日志通道
例如 /admin/xxx 走 admin 通道,/api/v1/xxx 走 api 通道。可在全局中间件中实现:
// app/middleware/LogChannelSwitch.php
public function handle($request, \Closure $next)
{
$path = trim($request->path(), '/');
if (strpos($path, 'admin/') === 0) {
Log::think()->setChannel('admin');
} elseif (strpos($path, 'api/') === 0) {
Log::think()->setChannel('api');
} elseif (strpos($path, 'swoole/') === 0) {
Log::think()->setChannel('swoole');
}
return $next($request);
}
并在 app/middleware.php 中注册,优先级设为 -100(确保早于 LoadLangPack 等中间件):
return [
\app\middleware\LogChannelSwitch::class => ['priority' => -100],
];
runtime 目录必须按通道物理隔离
ThinkPHP 的 runtime_path() 是共享的,若不手动分目录,所有通道日志会挤在同一个 log/ 下。务必在通道配置中用子目录区分:
runtime/log/admin/runtime/log/api/runtime/log/swoole/
同时确保 Web 服务器用户(如 www-data)对这些子目录有写权限:
mkdir -p runtime/log/{admin,api,swoole}
chmod -R 755 runtime/log
补充:Swoole 场景需额外注意
若项目含 Swoole 长连接服务(如 think-swoole),其日志不能复用 HTTP 通道。建议:
- 单独定义
swoole通道,path指向独立路径(如/var/log/tp81-swoole/) - 在 Swoole 启动脚本中手动初始化:
Log::init(config('log.channels.swoole')) - 避免在协程中混用
Log::channel(),应创建新实例并传入上下文
不复杂但容易忽略
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











