Loading

Laravel/Lumen 自定义错误日志格式

  • 有时需要完全控制已存在通道的 Monolog: 比如,你可能想要为给定通道的日志处理配置自定义的 MonologFormatterInterface
  • 实现:先在通道配置中定义一个 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"}

 

posted @ 2023-03-13 00:51  只要AD钙奶  阅读(558)  评论(0)    收藏  举报