Laravel/Lumen 自定义错误日志格式
- 有时需要完全控制已存在通道的
Monolog: 比如,你可能想要为给定通道的日志处理配置自定义的Monolog的FormatterInterface - 实现:先在通道配置中定义一个
tap 数组,tap 数组包含一个在通道创建后有机会用于自定义 Monolog 实例的类列表
格式化日志【 添加日志请求ID 】
1. 在 config/logging.php 创建对应的处理渠道
//自定义频道
'carverlog' => [
//日志驱动模式
'driver' => 'daily',
//日志存放路径
'path' => storage_path('logs/carver/carver.log'),
//自定义Monolog实例
'tap' => [App\Logging\MyLogFormatter::class],
//日志等级
'level' => 'info',
//日志分片周期,多少天一个文件
'days' => 7,
]
2. 在 app/Logging 目录下创建 MyLogFormatter 自定义 Monolog 实例的类
<?php
namespace App\Logging;
class MyLogFormatter
{
/**
* Customize the given logger instance.
* @param \Illuminate\Log\Logger $logger
* @return void
*/
public function __invoke($logger)
{
foreach ($logger->getHandlers() as $handler) {
$handler->setFormatter(new LineFormatters());
}
}
}
提示:【官方解释】一旦在通道中有了 tap 选项配置,就要准备用于自定义 Monolog 实例的类。这种类这需要一个方法: __invoke,它接受一个 Illuminate\Log\Logger 实例作为其参数。 Illuminate\Log\Logger 实例将所有方法调用代理到基础的 Monolog 实例:
<?php
namespace App\Logging;
class CustomizeFormatter
{
/**
* 自定义给定的日志实例。
*
* @param \Illuminate\Log\Logger $logger
* @return void
*/
public function __invoke($logger)
{
foreach ($logger->getHandlers() as $handler) {
$handler->setFormatter(...);
}
}
}
Tip:所有的 “tap” 类都是由 服务容器 解析的,因此任何依赖它们的构造器都会自动被注入。这段算是官方文档的说明了。
3. 在 app/Logging 目录下创建,用于重写 Monolog 的 LineFormatter 格式化处理器,LineFormatter 是 Monolog 默认的格式化处理器【例如:添加自定义uuid】
<?php
namespace App\Logging;
use Illuminate\Support\Str;
use Monolog\Formatter\LineFormatter as BaseLineFormatter;
use Monolog\Formatter\NormalizerFormatter;
class LineFormatters extends BaseLineFormatter
{
const NEW_SIMPLE_FORMAT = "[%datetime%] [%uuid%] %channel%.%level_name%: %message% %context% %extra%\n";
public function format(array $record)
{
$output = self::NEW_SIMPLE_FORMAT;
$vars = (new NormalizerFormatter())->format($record);
$vars['uuid'] = 'uuid:' . Str::uuid();
foreach ($vars['extra'] as $var => $val) {
if (false !== strpos($output, '%extra.' . $var . '%')) {
$output = str_replace('%extra.' . $var . '%', $this->stringify($val), $output);
unset($vars['extra'][$var]);
}
}
if (isset($vars['context']['exception']) && !empty($vars['context']['exception'])) {
$vars['message'] = '';
$vars['context'] = $vars['context']['exception'];
if (isset($vars['context']['trace'])) {
unset($vars['context']['trace']);
}
if (isset($vars['context']['previous'])) {
unset($vars['context']['previous']);
}
}
foreach ($vars as $var => $val) {
if (false !== strpos($output, '%' . $var . '%')) {
$output = str_replace('%' . $var . '%', $this->stringify($val), $output);
}
}
// remove leftover %extra.xxx% and %context.xxx% if any
if (false !== strpos($output, '%')) {
$output = preg_replace('/%(?:extra|context)\..+?%/', '', $output);
}
return $output;
}
}
4. 处理结果如下
[2023-03-12 16:34:10] [uuid:69bbd51e-bba2-4470-9eb4-21a409e85334] local.INFO: 提示信息 {"site_name":"carver","site_id":"1"} []
格式化日志【 格式化日志内容为JSON格式 】
1. 在格式化日志的 LineFormatters 文件中,需要重写 Monolog 的 JsonFormatter 格式化处理器
<?php
namespace App\Logging;
use Monolog\Formatter\JsonFormatter as BaseJsonFormatter;
class LineFormatters extends BaseJsonFormatter
{
/**
* @param array $record
* @return LineFormatters|array|bool|float|int|mixed|string|string[]|null
* @desc 格式化为Json格式
*/
public function format(array $record)
{
// 这个就是最终要记录的数组,最后转成Json并记录进日志
$newRecord = [
'datetime' => $record['datetime']->format('Y-m-d H:i:s'),
'message' => $record['message'],
'extra' => $record['extra'],
];
if (!empty($record['context'])) {
$newRecord = array_merge($newRecord, $record['context']);
}
// 这是最终返回的记录串,可以按自己的需求改
$json = $this->toJson($this->normalize($newRecord), true) . ($this->appendNewline ? "\n" : '');
return $json;
}
}
2. 处理结果如下
{"datetime":"2023-03-12 16:43:05","message":"提示信息","extra":[],"site_name":"carver","site_id":"1"}
本文来自博客园,作者:只要AD钙奶,转载请注明原文链接:https://www.cnblogs.com/carver/articles/17209928.html

浙公网安备 33010602011771号