作者:studytime(有問題可以到作者部落格下留言)
原文連結:https://www.studytime.xin
概述
Laravel/Lumen的日誌預設是基於Monolog進行的一層封裝,簡單使用的話文件還是很清晰的。
但是當我希望過濾錯誤日誌裡面的大量堆疊時候,以及一些其他自定義配置時,發現5.6版本之後對日誌系統做了升級。原有的configureMonologUsing自定義Monolog設定已經廢棄。參照新的文件和原始碼,重新做了封裝後,基本解決異常日誌堆疊問題。
構建自定義日誌通道
所有的應用程式日誌系統配置都位於 config/logging.php 配置檔案中。這個檔案允許你配置你的應用程式日誌通道,所以務必檢視每個可用的通道及它們的選項。
lumen 框架下該配置檔案可以在vendor包中找到對應的配置模板檔案,複製到config下,同時需要在bootstrap/app.php中註冊。
$app->configure($config);
針對具體的配置資訊簡單的在下文demo說明下:
<?php
// 配置檔案路徑:/config/logging.php
return [
// 預設用哪個
'default' => env('LOG_CHANNEL', 'stack'),
'channels' => [
//自定義頻道
'myapplog' => [
// 日誌驅動模式:
'driver' => 'daily',
// 日誌存放路徑
'path' => storage_path('logs/myapplog.log'),
// 日誌等級:
'level' => 'info',
// 日誌分片週期,多少天一個檔案
'days' => 1,
],
],
];
日誌使用
<?php
use Log;
class LogTestController extends Controller
{
$message = 'Some message';
$log = ['site_name'=>'studytime.xin','site_id'=>'1'];
Log::channel('myapplog')->info($message, $log); //Log後的陣列會自動轉成Json存到日誌記錄中
}
日誌寫入結果
[2020-03-01 10:22:28] local.INFO: Some message {'site_name':'studytime.xin','site_id':'1'}
高度自定義 Monolog 通道
有時需要完全控制已存在通道的 Monolog: 比如,你可能想要為給定通道的日誌處理配置自定義的 Monolog FormatterInterface 實現:
先在通道配置中定義一個 tap 陣列。 tap 陣列包含一個在通道建立後有機會用於自定義 Monolog 例項的類列表:
'single' => [
'driver' => 'single',
'tap' => [App\Logging\CustomizeFormatter::class],
'path' => storage_path('logs/laravel.log'),
'level' => 'debug',
],
一旦在通道中有了 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” 類都是由 服務容器 解析的,因此任何依賴它們的構造器都會自動被注入。這段算是官方文件的說明了。
如何實現自定義錯誤日誌格式、過濾大量異常日誌堆疊
在 config/logging.php 建立對應的處理渠道
'channels' => [
'custom' => [
'driver' => 'daily',
'path' => storage_path('logs/lumen.log'),
'tap' => [App\Logging\MyLogFormatter::class],
'days' => 1,
'level' => 'info',
],
],
在 app/Logging 目錄下建立 MyLogFormatter 自定義 Monolog 例項的類
<?php
namespace App\Logging;
class MyLogFormatter
{
public function __invoke($logger)
{
foreach ($logger->getHandlers() as $handler) {
$handler->setFormatter(new LineFormatter());
}
}
}
在 app/Logging 目錄下建立 用於重寫 Monolog 的 LineFormatter 格式化處理器
LineFormatter 是 Monolog 預設的格式化處理器
<?php
namespace App\Logging;
use Illuminate\Support\Str;
use Monolog\Formatter\LineFormatter as BaseLineFormatter;
use Monolog\Formatter\NormalizerFormatter;
class LineFormatter 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']);
}
}
if (false !== strpos($output, '%')) {
$output = preg_replace('/%(?:extra|context)\..+?%/', '', $output);
}
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;
}
}
異常日誌處理效果
[2020-03-03 21:42:36] [uuid:374b0045-7aef-4d4b-9ba0-fce13d8dd776] local.ERROR: {"class":"Illuminate\\Queue\\MaxAttemptsExceededException","message":"App\\Jobs\\DownloadReportDataJob has been attempted too many times or run too long. The job may have previously timed out.","code":0,"file":"/data/wwwroot/advertisingscript-line/vendor/illuminate/queue/Worker.php:601"} []
此時可以看到異常的日誌已經沒有大量的堆疊問題。
本作品採用《CC 協議》,轉載必須註明作者和本文連結