ThinkPHP的log
文章目录
- 环境
- ThinkPHP的log
- 配置
- 级别
- 写log
- SQL的log
- request的log
- response的log
- 参考
环境
- Windows 11 专业版
- XAMPP v3.3.0
- PHP 8.2.12
- ThinkPHP v8.1.3
ThinkPHP的log
ThinkPHP的log操作由 \think\Log
类完成,通常我们使用 think\facade\Log
类进行静态调用。
在 app/controller/Index.php
里添加 test1()
方法如下:
......
use think\facade\Log;
......public function test1() {Log::info('test1'); return 'OK';}
然后curl一下:
curl --silent -XGET "http://localhost:8000/index/test1"
此时,系统就会记录一条log。比如今天是2025年9月1号,在 runtime/log
目录下,会自动创建一个名为 202509
的目录,然后在该目录中创建 01.log
文件,如下:
配置
ThinkPHP的log配置文件是 config/log.php
,默认如下:
return [// 默认日志记录通道'default' => 'file',// 日志记录级别'level' => [],// 日志类型记录的通道 ['error'=>'email',...]'type_channel' => [],// 关闭全局日志写入'close' => false,// 全局日志处理 支持闭包'processor' => null,// 日志通道列表'channels' => ['file' => [// 日志记录方式'type' => 'File',// 日志保存目录'path' => '',// 单文件日志写入'single' => false,// 独立日志级别'apart_level' => [],// 最大日志文件数量'max_files' => 0,// 使用JSON格式记录'json' => false,// 日志处理'processor' => null,// 关闭通道日志写入'close' => false,// 日志输出格式化'format' => '[%s][%s] %s',// 是否实时写入'realtime_write' => false,],// 其它日志通道配置],];
基本上能做到顾名思义,而且默认配置看起来已经比较合理。
补充:如果想要设置单个log文件大小,可以加上 file_size
配置,比如:
'file_size' => 10485760, // 10 MB
如果log文件超出了限制,就会另存为一个以时间戳命名的文件。
级别
日志的级别从低到高依次为:
debug
info
notice
warning
error
critical
alert
emergency
默认的级别是 info
。
ThinkPHP额外增加了一个 sql
日志级别仅用于记录SQL日志(并且仅当开启数据库调试模式有效,详见下面的介绍)。
注意:系统发生异常后记录的日志级别是 error
。
在 app/controller/Index.php
里添加 test2()
方法如下:
public function test2() {throw new \think\Exception('出错啦!');}
然后访问该方法:
curl --silent -XGET "http://localhost:8000/index/test2"
log记录如下:
[2025-09-01T21:17:57+08:00][error] [0]出错啦!
写log
Log::record()
:记录日志信息到内存,系统在请求结束后会自动调用Log::save()
方法统一进行日志信息写入Log::write()
:实时写入一条日志信息Log::info()
:相当于Log::write(xxx, 'info')
,其它级别也同理
注意:前面提到,在配置文件 config/log.php
里, realtime_write
可以设置是否实时写入log,事实上该配置只影响 Log::record()
,不影响 Log::write()
,因为后者始终是实时写入的。
日志可以传入一个数组,并且被替换到日志内容中。
例如,在 app/controller/Index.php
里添加 test3()
方法如下::
public function test3() {Log::info('name: {name}, age: {age}', ['name' => 'Tom', 'age' => 20]);}
然后访问该方法:
curl --silent -XGET "http://localhost:8000/index/test3"
log记录如下:
[2025-09-01T21:26:32+08:00][info] name: Tom, age: 20
SQL的log
查看 config/database.php
的配置,默认如下:
......'trigger_sql' => env('APP_DEBUG', true),
......
查看 .env
里的 APP_DEBUG
配置:
APP_DEBUG = true
注意:在生产环境中, APP_DEBUG
一般会设置为false。如果希望显示SQL,可以直接把 trigger_sql
设置为true。
测试一下,在 app/controller/Index.php
里添加 test4()
方法如下::
......
use think\facade\Db;......public function test4() {$data = Db::table('t1')->where('c1', '>', 1)->select();return json($data);}
然后访问该方法:
curl --silent -XGET "http://localhost:8000/index/test4"
log记录如下:
[2025-09-01T21:44:36+08:00][sql] SELECT * FROM `t1` WHERE `c1` > 1 [ RunTime:0.000520s ]
request的log
如果能把ThinkPHP收到的request也记到log里,一来可以确认ThinkPHP是否收到了request,二来可以查看request的详细信息,帮助debug问题。
不过,貌似没有简单的配置可以记录request log,可以通过中间件(middleware)来完成。
首先创建中间件,可以用命令行操作(在项目根目录下):
php think make:middleware RequestLog
操作完成后,会在 app/middleware
目录下创建 RequestLog.php
文件如下:
<?php
declare (strict_types = 1);namespace app\middleware;class RequestLog
{/*** 处理请求** @param \think\Request $request* @param \Closure $next* @return Response*/public function handle($request, \Closure $next){}
}
修改 handle()
方法如下:
......
use think\facade\Log;
......public function handle($request, \Closure $next){// 记录请求信息$logData = ['ip' => $request->ip(),'method' => $request->method(),'url' => $request->url(),'params' => $request->param(),'header' => $request->header(),'user_agent' => $request->header('user-agent'),'time' => date('Y-m-d H:i:s')];Log::info('Request Received: ' . json_encode($logData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));return $next($request);}
}
可以根据需求,记录各种详细信息,注意可能会有一些敏感信息。
注意:如果担心中间件出问题影响后续操作,可以用 try...catch
包起来,这样即使记录log时出了问题,也不会影响对request的后续操作。
然后在 app/middleware.php
里注册中间件:
return [......\app\middleware\RequestLog::class,
];
现在,ThinkPHP就会把收到的request记录到log里,比如:
[2025-09-02T10:34:45+08:00][info] Request Received: {"ip": "111.201.72.246","method": "GET","url": "\/api\/index.php\/login\/checkLogin","params": [],"header": {"priority": "u=4","cookie": "PHPSESSID=0f117871cf16d58cf74f63cbba71963d","connection": "keep-alive","referer": "http:\/\/chinatt.org.cn\/","accept-encoding": "gzip, deflate","accept-language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2","accept": "*\/*","user-agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64; rv:142.0) Gecko\/20100101 Firefox\/142.0","host": "chinatt.org.cn"},"user_agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64; rv:142.0) Gecko\/20100101 Firefox\/142.0","time": "2025-09-02 10:34:45"
}
response的log
既然可以在处理request前记录request的log,那么同理,也可以在生成response后记录response的log。
修改 RequestLog.php
如下:
public function handle($request, \Closure $next){// 记录请求信息$logData = ['ip' => $request->ip(),'method' => $request->method(),'url' => $request->url(),'params' => $request->param(),'header' => $request->header(),'user_agent' => $request->header('user-agent'),'time' => date('Y-m-d H:i:s')];Log::info('Request Received: ' . json_encode($logData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));$response = $next($request);// 记录响应信息$logData = ['code' => $response->getCode(),'header' => $response->getHeader(),'content' => $response->getContent(),'time' => date('Y-m-d H:i:s')];Log::info('Response Sent: '. json_encode($logData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));return $response;}
可根据需求决定要记录哪些详细信息。另外,response有可能非常大,可能需要截取其中一部分。
参考
https://doc.thinkphp.cn/v8_0/log.html