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"}
作者:Carver-大脸猫
出处:https://www.cnblogs.com/carver/articles/17209928.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
转载请注明原处
本文来自博客园,作者:Carver-大脸猫,转载请注明原文链接:https://www.cnblogs.com/carver/articles/17209928.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现