laravel 5.6日誌理解及日誌格式定義

Laravel/Lumen的日誌簡單系統介紹:

Laravel/Lumen的日誌默認是基於Monolog進行了一層封裝,如果要求不高,用起來還是十分容易的,本文基於laravel5.6/Lumen5.6版本進行解說。5.6版對日誌系統做了升級,將日誌的配置單獨放以了config/logging.php 配置文件中,所以現在實用多了。


基本配置(解決日誌路徑文件名和保存週期等)

開始使用Laravel5.5時經常遇到有人問Laravel中日誌的爲什麼只有一個文件,能不能修改日誌目錄,能不能修改日誌文件名?剛開始用時我也有這樣的困惑,由於早期項目簡單(其實是懶),沒有去深入研究。後來跟到了5.6,官方終於發飆了,完美通過配置解決問題(5.5的版本其實也有解決方案,可以自行搜索一下,順便吐槽一下Lavavel官方文檔太簡單了,感覺一大半的強大功能都沒有提及如何深度使用)。以下代理示例,大概的備註了一下參數說明,還有一些可以挖掘。

 

<?php
// 配置文件路徑:/config/logging.php
return [
    // 默認用哪個
    'default' => env('LOG_CHANNEL', 'stack'),

    'channels' => [
        //自定義頻道
        'myapplog' => [
            // 日誌驅動模式:
            'driver' => 'daily',                            
            // 日誌存放路徑
            'path' => storage_path('logs/myapplog.log'),
            // 日誌等級:
            'level' => 'info',
            // 日誌分片週期,多少天一個文件
            'days' => 1,
        ],

        // 系統默認,可以合併幾個頻道,按等級對應記錄,符合等級條件的都記錄
        'stack' => [
            'driver' => 'stack',
            'channels' => ['single','daily'],
        ],
        'single' => [
            'driver' => 'single',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
        ],
        'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'info',
            'days' => 7,
        ],
    ],
];

日誌使用:

 

<?php
use Log;

class LogTestController extends Controller
{
  $message = 'Some message';
  $log = ['user_id'=>1,'user_name'=>'abcd']; 
  Log::channel('myapplog')->info($message, $log);  //Log後的數組會自動轉成Json存到日誌記錄中

查看記錄到的效果:

 

[2018-02-23 10:22:28] local.INFO: Some message {'user_id':1,'user_name':'abcd'}

高階定製:(完全定義日誌格式,本例爲全Json格式)

踩了好多坑,開始嘗試直接自己 new 一個 monolog 的方案,雖然也實現了全 Json 記錄了,但有很多不想要的字段。達不到要求。
幾經折騰,發現 Monolog 有很多可以用的 Formatter ,但發現官方的把字段寫死在裏邊了,抓狂到了想直接改官方源碼的齷齪地步了,還是不死心,最終發現Laravel5.6的logging參數中有一個tap的接口可以用。順着這條線,最終通過重定義 Formatter 的 format() 方法實現了需求 :
1、配置logging.php中的 tap項:

 

return [
    'default' => env('LOG_CHANNEL', 'myapplog'),
    'channels' => [
        'myapplog' => [
            'driver' => 'daily',                            
            'path' => storage_path('logs/myapplog.log'),
            // 掛載日誌格式接口(重點)
            'tap' => [App\Logging\ApplogFormatter::class],
            'level' => 'info',
            'days' => 1,
        ],
    ],
];

新建App/Logging/ApplogFormatter.php

 

<?php
namespace App\Logging;

use App\Logging\JsonFormatter;

class ApplogFormatter
{
    /**
     * Customize the given logger instance.
     *
     * @param  \Illuminate\Log\Logger  $logger
     * @return void
     */
    public function __invoke($logger)
    {
        foreach ($logger->getHandlers() as $handler) {
            $handler->setFormatter(new JsonFormatter());
        }
    }
}

重點:新建/App/Logging/JsonFormatter.php

 

<?php
namespace App\Logging;

use Monolog\Formatter\JsonFormatter as BaseJsonFormatter;

class JsonFormatter extends BaseJsonFormatter
{
    public function format(array $record)
    {
        // 這個就是最終要記錄的數組,最後轉成Json並記錄進日誌
        $newRecord = [
            'time' => $record['datetime']->format('Y-m-d H:i:s'),
            'message' => $record['message'],
        ];

        if (!empty($record['context'])) {
            $newRecord = array_merge($newRecord, $record['context']);
        }
        //$json = 'aaa,bbb,ccc';  // 這是最終返回的記錄串,可以按自己的需求改
        $json = $this->toJson($this->normalize($newRecord), true) . ($this->appendNewline ? "\n" : '');

        return $json;
    }
}

Log的記錄方法還是一樣用:

 

class LogTestController extends Controller
{
  $message = 'Some message';
  $log = ['user_id'=>1,'user_name'=>'abcd']; 
  Log::channel('myapplog')->info($message, $log);  //Log後的數組會自動轉成Json存

看看最終的效果:

 

{"time":"2018-06-09 13:39:39","message":"Some message","user_id":1,"user_name":"abcd"}

大功告成!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章