【Laravel官方文件導讀】Logging日誌全攻略

【Laravel官方文件導讀】Logging日誌全攻略

為了幫助你更多的了解應用中到底發生了什麼,Laravel 提供了強大的日誌服務,允許你將日誌消息、系統錯誤日誌記錄到檔案中,甚至使用 Slack 通知到你的整個團隊

Laravel的日誌是以頻道來做為基底,每一個頻道代表一種特定的方式來記錄日誌資訊。例如 single 頻道寫日誌訊息到單一的日誌檔案,而 slack 頻道發送日誌訊息到 slack。而日誌訊息可以根據它們的需要寫入到多個頻道中

在 Laravel 框架中,Laravel 使用 Monolog 函式庫,它為各種強大的日誌處理提供支持。Laravel 使設定這些處理程序變得簡單,允許你混合並匹配它們自定義的應用日誌處理

設定

所有的應用日誌系統配置都位於 config/logging.php 設定文件中。這個檔案允許你設定你的應用日誌頻道,所以務必查看每個可用的頻道及它們的選項。我們將在下面介紹一些常用的選項

預設情況下,Laravel 將使用 stack 頻道去記錄日誌消息。stack 頻道被用來將多個日誌頻道聚合到一個單一的頻道中。關於堆疊的更多訊息,查看下面更多的內容

設定頻道名稱

預設情況下,Monolog 使用與當前環境匹配的『頻道名稱』進行實例化,比如 production 或者 local。要改變這個值,需添加一個 name 選項到你的頻道配置中:

'stack' => [
    'driver' => 'stack',
    'name' => 'channel-name',
    'channels' => ['single', 'slack'],
],

可用的頻道驅動

每一個日誌頻道是利用驅動來得到能力。該驅動決定日誌訊息是如何又是在哪裡被記錄下來。下面列出的每一個頻道驅動將能夠被每個 Laravel 應用使用。大多數的這些驅動已經列在應用的 config/logging.php 裏頭,所以盡量多去看看這個檔案並熟悉裏頭的內容

名稱 描述
custom 一個便於創建『多頻道』頻道的包裝器
daily 一個每天輪換的基於 Monolog 驅動的 RotatingFileHandler
errorlog 一個基於 Monolog 驅動的 ErrorLogHandle
monolog 一個 Monolog 工廠驅動能使用任何有支持的 Monolog handler
null 一個驅動放棄所有的日誌訊息
papertrail 一個基於 Monolog 驅動的 SyslogUdpHandler
single 單個檔案或者基於日誌頻道的路徑 (StreamHandler)
slack 一個基於 Monolog 驅動的 SlackWebhookHandler
stack 一個便於創建『多頻道』頻道的包裝器
syslog 一個基於 Monolog 驅動的 SyslogHandler

確認進階頻道自定義文件來了解更多關於 monolog 和自定義驅動

頻道配置

設定 Single 和 Daily 頻道

single 和 daily 頻道包含三個可選配置項:bubble、permission 和 locking 名稱 描述 預設值
bubble 消息處理後,指示消息是否推送到其他頻道 true
permission 日誌文件權限 0644
locking 寫入之前嘗試鎖定日誌文件 false

設定 Papertrail 頻道

papertrail 頻道需要 url 和 port 配置選項,你可以從 Papertrail 獲取這些值

設定 Slack 頻道

slack 頻道需要 url 配置選項。這個 URL 應當與你為 Slack 團隊配置的一個 incoming webhook 相匹配。預設情況下,Slack 只會接收 critical 和更高等級的日誌,你可以在 logging 設定文件中對其進行修改。

建立日誌堆疊

前面說過,stack 驅動允許你在單一日誌頻道中整合多個頻道。讓我們通過一個產品級應用的配置實例來看看如何使用日誌堆疊:

'channels' => [
    'stack' => [
        'driver' => 'stack',
        'channels' => ['syslog', 'slack'],
    ],

    'syslog' => [
        'driver' => 'syslog',
        'level' => 'debug',
    ],

    'slack' => [
        'driver' => 'slack',
        'url' => env('LOG_SLACK_WEBHOOK_URL'),
        'username' => 'Laravel Log',
        'emoji' => ':boom:',
        'level' => 'critical',
    ],
],

我們來分析這個配置。首先要注意的是 stack 通過藉助它的 channels 選項聚合了另外兩個頻道:syslog 和 slack。因此,在記錄日誌消息時,這兩個頻道都有機會完成日誌消息記錄。然而這些頻道是否真能記錄這些訊息將要看訊息的階層/等級

日誌階層

請留意上面例子中 syslog 和 slack 中的 level 配置。這個選項決定了需要被該頻道記錄的日誌的最低 「級別」。Monolog (一個功能強勁的 Laravel 日誌服務)接受定義在 RFC 5424 specification 中的全部級別: emergency、alert、critical、error、warning、notice、info 和 debug

假設我們使用 debug 方法記錄日誌消息:

Log::debug('An informational message.');

根據我們的配置,syslog 頻道將把該消息記錄到系統日誌;不過因為錯誤消息不是 critical 或更高級別,它將不會被發送到 Slack。如果我們記錄一條 emergency 消息的話,由於 emergency 的級別高於兩個頻道的最低級別限制,它將被發送給系統日誌和 Slack:

Log::emergency('The system is down!');

撰寫日誌訊息

你可以使用 Log Facade 來將訊息寫入日誌。如前所述,日誌提供定義在 RFC 5424 specification 中的可用日誌級別: emergency、alert、critical、error、warning、notice、info 和 debug:

use Illuminate\Support\Facades\Log;

Log::emergency($message);
Log::alert($message);
Log::critical($message);
Log::error($message);
Log::warning($message);
Log::notice($message);
Log::info($message);
Log::debug($message);

因此,你可以呼叫這些方法中的任一方法記錄相應級別的日誌。預設情況下,消息被寫入到在 config/logging.php 設定文件中定義的預設日誌頻道:

//app\Http\Controllers\UserController.php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Support\Facades\Log;

class UserController extends Controller
{
    /**
     * Show the profile for the given user.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        Log::info('Showing the user profile for user: '.$id);

        return view('user.profile', [
            'user' => User::findOrFail($id)
        ]);
    }
}

上下文訊息

可以將上下文訊息陣列傳遞給日誌方法。這些訊息將被格式化,並與日誌消息一起顯示:

Log::info('使用者登入失敗.', ['id' => $user->id]);

寫到指定通道

有時候你可能希望將消息寫入到應用預設頻道之外的頻道中。可以使用 Log Facade 的 channel() 獲取定義在配置文件中的任一頻道並將訊息寫入其中:

use Illuminate\Support\Facades\Log;

Log::channel('slack')->info('Something happened!');

如果想要建立一個由多頻道構成的按需記錄的堆疊,可以使用 stack() :

Log::stack(['single', 'slack'])->info('Something happened!');

自定義 Monolog 通道

為通道自定義 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 實例:

//app\Logging\CustomizeFormatter.php

namespace App\Logging;

use Monolog\Formatter\LineFormatter;

class CustomizeFormatter
{
    /**
     * Customize the given logger instance.
     *
     * @param  \Illuminate\Log\Logger  $logger
     * @return void
     */
    public function __invoke($logger)
    {
        foreach ($logger->getHandlers() as $handler) {
            $handler->setFormatter(new LineFormatter(
                '[%datetime%] %channel%.%level_name%: %message% %context% %extra%'
            ));
        }
    }
}

技巧:

所有的 「tap」 類別都是由服務容器解析的,因此任何依賴它們的建構子都會自動被注入

自定義 Monolog 頻道

創建 Monolog 處理器頻道

Monolog 有多種可用處理器。在某些情況下,你會希望僅建立一個帶有指定處理器的 Monolog 驅動的日誌類型。這些頻道可以使用 monolog 驅動建立

在使用 monolog 驅動時, handler 配置項用於指定被實例化的處理器。如果該處理器的建構子需要參數,可以使用可選的 with 配置項來指定:

'logentries' => [
    'driver'  => 'monolog',
    'handler' => Monolog\Handler\SyslogUdpHandler::class,
    'with' => [
        'host' => 'my.logentries.internal.datahubhost.company.com',
        'port' => '10000',
    ],
],
Monolog 格式化

使用 monolog 驅動時,Monolog 的 LineFormatter 用於預設的格式化處理器。當然你也可以使用 formatter 和 formatter_with 配置項自定義格式化處理器類型:

'browser' => [
    'driver' => 'monolog',
    'handler' => Monolog\Handler\BrowserConsoleHandler::class,
    'formatter' => Monolog\Formatter\HtmlFormatter::class,
    'formatter_with' => [
        'dateFormat' => 'Y-m-d',
    ],
],

如果所用的 Monolog 處理器能夠提供自帶的格式代處理器,可以將 formatter 配置項指定為 default:

'newrelic' => [
    'driver' => 'monolog',
    'handler' => Monolog\Handler\NewRelicHandler::class,
    'formatter' => 'default',
],

通過工廠創建自定義頻道

如果你想定義一個完全自定義的頻道,你可以完全控制 Monolog 的實例化和配置,你可以在 config/logging.php 配置文件中指定 custom 驅動程序類型。 你的配置應該包含一個 via 選項,指向將被呼叫以建立 Monolog 實例的工廠類別:

'channels' => [
    'example-custom-channel' => [
        'driver' => 'custom',
        'via' => App\Logging\CreateCustomLogger::class,
    ],
],

一旦配置了 custom 頻道,就可以定義創建 Monolog 實例的類別。 這個類別只需要一個方法: __invoke,它就可以回傳 Monolog 實例,該方法將接收頻道設定陣列做為單一參數:

//app\Logging\CreateCustomLogger.php

namespace App\Logging;

use Monolog\Logger;

class CreateCustomLogger
{
    /**
     * Create a custom Monolog instance.
     *
     * @param  array  $config
     * @return \Monolog\Logger
     */
    public function __invoke(array $config)
    {
        return new Logger(...);
    }
}

分享這篇文章:

關聯文章:

訂閱電子報,索取 Laravel 學習手冊

價值超過 3000 元,包含常用 Laravel 語法與指令!

Laravel 百萬年薪特訓營

從最基礎的 PHP 語法開始,包含所有你該知道的網頁基礎知識,連同 Laravel 從零開始一直到實戰,最後還將告訴你如何找好工作,讓你及早擁有百萬年薪