Laravel 实现使用中间件记录所有请求信息以及日志纯 JSON 格式保存
欢迎阅读本文,希望能给与你一定的帮助,Laravel 新人一枚,技术不过关,如有撰写错误的地方,恳请不吝赐教!
Laravel 常规写入的 Log 是这样的,带有日期和日志类型:
[2020-04-10 09:37:23] local.INFO: record request message
本文最终实现写入的 Log 记录是纯 Json 格式保存:
{"datetime":"2020-04-10 09:27:36","message":"record request message","url":"URL","method":"POST"}
配置 config/logging.php
#
新增自定义通道 request
,有时需要完全控制已存在通道的 Monolog: 比如,你可能想要为给定通道的日志处理配置自定义的 Monolog FormatterInterface 实现。
先在通道配置中定义一个 tap 数组
。 tap 数组包含一个在通道创建后有机会用于自定义 Monolog 实例的类列表。
return [
'channels' => [
'request' => [
'driver' => 'daily',
'path' => storage_path('logs/request.log'),
'level' => 'info',
'days' => 5,
'tap' => [App\Logging\CustomizeFormatter::class],
'value_max_length' => env('REQUEST_LOG_VALUE_MAX_LENGTH', 300),
],
]
]
创建 app/Logging/CustomizeFormatter.php
文件#
<?php
namespace App\Logging;
use App\Logging\CustomizeJsonFormatter;
class CustomizeFormatter
{
/**
* 自定义给定的日志实例。
*
* @param \Illuminate\Log\Logger $logger
* @return void
*/
public function __invoke($logger)
{
foreach ($logger->getHandlers() as $handler) {
$handler->setFormatter(new CustomizeJsonFormatter());
}
}
}
创建 app/Logging/CustomizeJsonFormatter.php
文件#
<?php
namespace App\Logging;
use Monolog\Formatter\JsonFormatter;
class CustomizeJsonFormatter extends JsonFormatter
{
// 重构
public function format(array $record): string
{
$newRecord = [
'datetime' => $record['datetime']->format('Y-m-d H:i:s'),
'message' => $record['message'],
];
if (!empty($record['context'])) {
$newRecord = array_merge($newRecord, $record['context']);
}
$json = $this->toJson($this->normalize($newRecord), true) . ($this->appendNewline ? "\n" : '');
return $json;
}
}
创建中间件命令:php artisan make:middleware RecordRequestMessage
#
命令执行后,文件会生成在 app/Http/Middleware/RecordRequestMessage.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
class RecordRequestMessage
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
// 记录所有请求信息
$requestMessage = [
'url' => $request->url(),
'method' => $request->method(),
'ip' => $request->ips(),
'path' => $request->path(),
'headers' => $request->header(),
'query' => $request->query()
];
if ($request->file()) {
// 文件内容不做日志记录,使用<file>做标识
$requestMessage['body'] = '<file>';
}
else {
// 获取请求体Body信息
$bodyContent = $request->all();
// 从.env文件中获取参数内容的长度
$parameterLength = \config('logging.channels.request.value_max_length');
if ($bodyContent && in_array($request->method(), ['POST', 'PATCH']))
{
foreach ($request->all() as $key => $value) {
if (Str::length($value) > $parameterLength) {
// 参数内容的长度过大的进行裁剪
$bodyContent[$key] = Str::limit($value, $parameterLength);
}
}
}
$requestMessage['body'] = $bodyContent;
}
Log::channel('request')->info('record request message', $requestMessage);
return $next($request);
}
}
在 app/Http/Kernel.php
加入全局中间件#
protected $middleware = [
\App\Http\Middleware\RecordRequestMessage::class,
];
最后访问请求站点,即可在 storage/logs/request-xxxx.log
中看到日志最终效果#
{"datetime":"2020-04-10 09:27:36","message":"record request message","url":"URL","method":"POST"}
后续:精简版#
只需要配置 config/logging.php
使用内置的 Monolog 方法实现即可,不需要配置 tap数组
use Monolog\Formatter\JsonFormatter;
use Monolog\Handler\StreamHandler;
return [
'channels' => [
'request' => [
'driver' => 'daily',
'path' => storage_path('logs/request.log'),
'level' => 'info',
'days' => 5,
'handler' => StreamHandler::class,
'formatter' => JsonFormatter::class,
'value_max_length' => env('REQUEST_LOG_VALUE_MAX_LENGTH', 300),
],
]
]
日志《Laravel 7 中文文档》上没有介绍到 handler
、formatter
这些配置项,对新手而然容易忽略这些便捷的实现方法,从而使用较为复杂的方式来实现最终效果,可查阅官网 https://learnku.com/docs/laravel/7.x/logging#creat... 以及 Monolog 的文档 https://github.com/Seldaek/monolog
参考#
日志《Laravel 7 中文文档》
中间件《Laravel 7 中文文档》
https://www.jianshu.com/p/b8e0ef4ef249
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: