Custom Formatter of the Logger
PHP:7.2
Laravel:5.8
Laravel 本身提供了很好的 Log 機制,大部份的時候都可以透過原本 Framework 內建的方法解決大部份的 log 需求。
但也因為 Framework 都包裝好了,因此如果需要自訂 Log Format
就必須另外自行處理。
以下就以『將 log 轉成 JSON
形式儲存』當範例。
Create Formatter
Laravel 的 Log
底層是透過 Monolog
去寫入 log 的,因此我們需要從 Monolog\Formatter
下手,才能處理我們要的 Formatter。
app/Components/JsonFormatter.php
namespace App\Components;
// 繼承 Monolog 的 JsonFormatter 來達到我們的需求
use Monolog\Formatter\JsonFormatter as BaseJsonFormatter;
class JsonFormatter extends BaseJsonFormatter
{
public function format(array $record)
{
// 加入我們需要的資料
$newRecord = [
'time' => $record['datetime']->format('Y-m-d H:i:s'),
// message 就是我們原本的 log
// 注意:這邊的 log 已經被轉換成字串了,並不會是 array,因此建議直接以 JSON 傳遞資料
'result' => json_decode($record['message'], true),
];
// Contextual Information
if (!empty($record['context'])) {
$newRecord = array_merge($newRecord, $record['context']);
}
// 轉換成 JSON 並換行
$json = $this->toJson($newRecord) . ($this->appendNewline ? "\n" : '');
return $json;
}
}
Create Logger
接著我們需要定義一個 Logger
,並載入剛剛的 Formatter
,再讓 Framework 直接使用此 Logger
。
app/Services/LogService.php
namespace App\Services;
use App\Components\JsonFormatter;
class LogService
{
/**
* Customize the given logger instance.
*
* @param \Illuminate\Log\Logger $logger
* @return void
*/
public function __invoke($logger)
{
foreach ($logger->getHandlers() as $handler) {
// 設定 JsonFormatter
$handler->setFormatter(new JsonFormatter());
}
}
}
Logging Config
在 Laravel 中,可以透過 config/logging.php
這支設定檔裡控制不同的 log channels
,因此我們可以自行改寫或定義自己的 channel。
config/logging.php
[
'channels' => [
// 新建一個 access channel
'access' => [
// daily driver 可以讓 log file 以 date 方式呈現
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
// 透過 tap 參數載入自行定義的 Logger
'tap' => [App\Services\LogService::class],
'level' => 'debug',
]
],
]
Usage
接著透過原本 Laravel 提供寫入 log 的方式就可以完成啦!
Log::channel('access')->info(json_encode('This is TEST'));