記錄
簡介
為了幫助您深入了解應用程式內部的運作情況,Laravel 提供了強大的記錄服務,可讓您將訊息記錄到檔案、系統錯誤記錄,甚至可以發送到 Slack 來通知您的整個團隊。
Laravel 記錄基於「通道」。每個通道代表一種特定的寫入記錄資訊方式。例如,single
通道會將記錄檔寫入單一記錄檔,而 slack
通道會將記錄訊息發送到 Slack。記錄訊息可能會根據其嚴重性寫入多個通道。
在底層,Laravel 使用 Monolog 函式庫,該函式庫為各種強大的記錄處理常式提供支援。Laravel 讓設定這些處理常式變得輕而易舉,讓您可以混合搭配它們來自訂應用程式的記錄處理方式。
設定
所有控制應用程式記錄行為的設定選項都放在 config/logging.php
設定檔中。此檔案可讓您設定應用程式的記錄通道,因此請務必檢查每個可用的通道及其選項。我們將在下面檢閱一些常見的選項。
依預設,Laravel 在記錄訊息時會使用 stack
通道。stack
通道用於將多個記錄通道匯總到單一通道中。如需更多關於建立堆疊的資訊,請查看下面的文件。
可用的通道驅動程式
每個記錄通道都由「驅動程式」提供支援。驅動程式決定實際記錄記錄訊息的方式和位置。每個 Laravel 應用程式中都有以下記錄通道驅動程式。大多數這些驅動程式的條目都已存在於您應用程式的 config/logging.php
設定檔中,因此請務必檢查此檔案以熟悉其內容
名稱 | 描述 |
---|---|
custom |
一個呼叫指定的工廠來建立通道的驅動程式。 |
daily |
一個基於 RotatingFileHandler 的 Monolog 驅動程式,每天輪換。 |
errorlog |
一個基於 ErrorLogHandler 的 Monolog 驅動程式。 |
monolog |
一個 Monolog 工廠驅動程式,可以使用任何支援的 Monolog 處理常式。 |
papertrail |
一個基於 SyslogUdpHandler 的 Monolog 驅動程式。 |
single |
一個基於單一檔案或路徑的記錄器通道 (StreamHandler )。 |
slack |
一個基於 SlackWebhookHandler 的 Monolog 驅動程式。 |
stack |
一個用於方便建立「多通道」通道的包裝器。 |
syslog |
一個基於 SyslogHandler 的 Monolog 驅動程式。 |
請查看關於進階通道自訂的文件,以深入了解 monolog
和 custom
驅動程式。
設定通道名稱
依預設,Monolog 會使用與目前環境相符的「通道名稱」來例項化,例如 production
或 local
。若要變更此值,您可以將 name
選項新增至通道的設定中
'stack' => [ 'driver' => 'stack', 'name' => 'channel-name', 'channels' => ['single', 'slack'],],
通道先決條件
設定 Single 和 Daily 通道
single
和 daily
通道有三個可選的設定選項:bubble
、permission
和 locking
。
名稱 | 描述 | 預設值 |
---|---|---|
bubble |
指示在處理訊息後,是否應將訊息向上傳遞到其他通道。 | true |
locking |
嘗試在寫入記錄檔之前鎖定它。 | false |
permission |
記錄檔的權限。 | 0644 |
此外,daily
通道的保留原則可以透過 LOG_DAILY_DAYS
環境變數或設定 days
設定選項來設定。
名稱 | 描述 | 預設值 |
---|---|---|
days |
應該保留每日記錄檔的天數。 | 14 |
設定 Papertrail 通道
papertrail
通道需要 host
和 port
設定選項。這些選項可以透過 PAPERTRAIL_URL
和 PAPERTRAIL_PORT
環境變數來定義。您可以從 Papertrail 取得這些值。
設定 Slack 通道
slack
通道需要 url
設定選項。此值可以透過 LOG_SLACK_WEBHOOK_URL
環境變數來定義。此 URL 應與您為 Slack 團隊設定的傳入 Webhook 的 URL 相符。
依預設,Slack 只會接收 critical
級別及以上的記錄;但是,您可以使用 LOG_LEVEL
環境變數或修改 Slack 記錄通道設定陣列中的 level
設定選項來調整此級別。
記錄棄用警告
PHP、Laravel 和其他函式庫通常會通知其使用者,某些功能已被棄用,並將在未來版本中移除。如果您想要記錄這些棄用警告,您可以使用 LOG_DEPRECATIONS_CHANNEL
環境變數,或在您應用程式的 config/logging.php
設定檔中指定您偏好的 deprecations
記錄通道
'deprecations' => [ 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), 'trace' => env('LOG_DEPRECATIONS_TRACE', false),], 'channels' => [ // ...]
或者,您可以定義一個名為 deprecations
的記錄通道。如果存在具有此名稱的記錄通道,則它將始終用於記錄棄用
'channels' => [ 'deprecations' => [ 'driver' => 'single', 'path' => storage_path('logs/php-deprecation-warnings.log'), ],],
建立記錄堆疊
如前所述,stack
驅動程式可讓您為了方便起見,將多個通道合併到單一記錄通道中。為了說明如何使用記錄堆疊,讓我們看看您可能會在生產應用程式中看到的一個範例設定
'channels' => [ 'stack' => [ 'driver' => 'stack', 'channels' => ['syslog', 'slack'], 'ignore_exceptions' => false, ], 'syslog' => [ 'driver' => 'syslog', 'level' => env('LOG_LEVEL', 'debug'), 'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER), 'replace_placeholders' => true, ], 'slack' => [ 'driver' => 'slack', 'url' => env('LOG_SLACK_WEBHOOK_URL'), 'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'), 'emoji' => env('LOG_SLACK_EMOJI', ':boom:'), 'level' => env('LOG_LEVEL', 'critical'), 'replace_placeholders' => true, ],],
讓我們分析這個設定。首先,請注意我們的 stack
通道透過其 channels
選項匯總了另外兩個通道:syslog
和 slack
。因此,在記錄訊息時,這兩個通道都有機會記錄訊息。但是,如下所示,這些通道是否實際記錄訊息可能會由訊息的嚴重性 /「級別」來決定。
記錄級別
請注意以上範例中 syslog
和 slack
通道配置中的 level
配置選項。此選項決定了訊息必須達到的最低「級別」才能被該通道記錄。為 Laravel 日誌服務提供動力的 Monolog,提供了 RFC 5424 規範中定義的所有日誌級別。依嚴重程度由高至低排列,這些日誌級別為:emergency(緊急)、alert(警報)、critical(嚴重)、error(錯誤)、warning(警告)、notice(注意)、info(資訊)和 debug(除錯)。
因此,假設我們使用 debug
方法記錄一則訊息。
Log::debug('An informational message.');
根據我們的設定,syslog
通道會將訊息寫入系統日誌;然而,由於錯誤訊息的級別未達到 critical
或更高,因此不會發送到 Slack。但是,如果我們記錄一則 emergency
訊息,則會同時發送到系統日誌和 Slack,因為 emergency
級別高於兩個通道的最低級別閾值。
Log::emergency('The system is down!');
寫入記錄訊息
您可以使用 Log
門面將資訊寫入日誌。如前所述,日誌記錄器提供了 RFC 5424 規範中定義的八個日誌級別: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);
您可以呼叫任何這些方法來記錄對應級別的訊息。預設情況下,訊息將會寫入由您的 logging
設定檔設定的預設日誌通道。
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Models\User;use Illuminate\Support\Facades\Log;use Illuminate\View\View; class UserController extends Controller{ /** * Show the profile for the given user. */ public function show(string $id): View { Log::info('Showing the user profile for user: {id}', ['id' => $id]); return view('user.profile', [ 'user' => User::findOrFail($id) ]); }}
情境資訊
可以將一個關聯資料陣列傳遞給日誌方法。這些關聯資料將會格式化並與日誌訊息一同顯示。
use Illuminate\Support\Facades\Log; Log::info('User {id} failed to login.', ['id' => $user->id]);
有時,您可能希望指定一些關聯資訊,這些資訊應包含在特定通道的所有後續日誌條目中。例如,您可能希望記錄與應用程式的每個傳入請求相關聯的請求 ID。要實現這一點,您可以呼叫 Log
門面的 withContext
方法。
<?php namespace App\Http\Middleware; use Closure;use Illuminate\Http\Request;use Illuminate\Support\Facades\Log;use Illuminate\Support\Str;use Symfony\Component\HttpFoundation\Response; class AssignRequestId{ /** * Handle an incoming request. * * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ public function handle(Request $request, Closure $next): Response { $requestId = (string) Str::uuid(); Log::withContext([ 'request-id' => $requestId ]); $response = $next($request); $response->headers->set('Request-Id', $requestId); return $response; }}
如果您想要在所有日誌通道之間共享關聯資訊,您可以呼叫 Log::shareContext()
方法。此方法將為所有已建立的通道和後續建立的任何通道提供關聯資訊。
<?php namespace App\Http\Middleware; use Closure;use Illuminate\Http\Request;use Illuminate\Support\Facades\Log;use Illuminate\Support\Str;use Symfony\Component\HttpFoundation\Response; class AssignRequestId{ /** * Handle an incoming request. * * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ public function handle(Request $request, Closure $next): Response { $requestId = (string) Str::uuid(); Log::shareContext([ 'request-id' => $requestId ]); // ... }}
如果您需要在處理佇列任務時共享日誌關聯資訊,您可以使用任務中介軟體。
寫入特定通道
有時您可能希望將訊息記錄到應用程式預設通道以外的其他通道。您可以使用 Log
門面上的 channel
方法來檢索並記錄到設定檔中定義的任何通道。
use Illuminate\Support\Facades\Log; Log::channel('slack')->info('Something happened!');
如果您想要建立一個由多個通道組成的按需日誌堆疊,您可以使用 stack
方法。
Log::stack(['single', 'slack'])->info('Something happened!');
按需通道
也可以透過在執行時提供設定,而無需該設定存在於應用程式的 logging
設定檔中,來建立按需通道。要實現這一點,您可以將設定陣列傳遞給 Log
門面的 build
方法。
use Illuminate\Support\Facades\Log; Log::build([ 'driver' => 'single', 'path' => storage_path('logs/custom.log'),])->info('Something happened!');
您可能還希望將按需通道包含在按需日誌堆疊中。這可以透過將按需通道實例包含在傳遞給 stack
方法的陣列中來實現。
use Illuminate\Support\Facades\Log; $channel = Log::build([ 'driver' => 'single', 'path' => storage_path('logs/custom.log'),]); Log::stack(['slack', $channel])->info('Something happened!');
Monolog 通道自訂
自訂通道的 Monolog
有時,您可能需要完全控制如何為現有通道設定 Monolog。例如,您可能想要為 Laravel 的內建 single
通道設定自訂的 Monolog FormatterInterface
實作。
首先,在通道的設定上定義一個 tap
陣列。tap
陣列應包含在 Monolog 實例建立後應有機會自訂(或「點擊」進入)的類別列表。這些類別應該放在哪裡沒有慣例,因此您可以自由地在應用程式中建立一個目錄來存放這些類別。
'single' => [ 'driver' => 'single', 'tap' => [App\Logging\CustomizeFormatter::class], 'path' => storage_path('logs/laravel.log'), 'level' => env('LOG_LEVEL', 'debug'), 'replace_placeholders' => true,],
一旦您在通道上設定了 tap
選項,您就可以定義將自訂 Monolog 實例的類別。這個類別只需要一個方法:__invoke
,它會接收一個 Illuminate\Log\Logger
實例。Illuminate\Log\Logger
實例將所有方法呼叫代理到基礎的 Monolog 實例。
<?php namespace App\Logging; use Illuminate\Log\Logger;use Monolog\Formatter\LineFormatter; class CustomizeFormatter{ /** * Customize the given logger instance. */ public function __invoke(Logger $logger): void { foreach ($logger->getHandlers() as $handler) { $handler->setFormatter(new LineFormatter( '[%datetime%] %channel%.%level_name%: %message% %context% %extra%' )); } }}
您所有的「點擊」類別都由服務容器解析,因此它們需要的任何建構子相依性都會自動注入。
建立 Monolog 處理常式通道
Monolog 有各種可用的處理器,而 Laravel 並未包含每個處理器的內建通道。在某些情況下,您可能希望建立一個自訂通道,該通道僅是沒有對應 Laravel 日誌驅動程式的特定 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 處理器
Monolog 也可以在記錄訊息之前處理它們。您可以建立自己的處理器,或使用Monolog 提供的現有處理器。
如果您想要自訂 monolog
驅動程式的處理器,請將 processors
設定值新增至通道的設定。
'memory' => [ 'driver' => 'monolog', 'handler' => Monolog\Handler\StreamHandler::class, 'with' => [ 'stream' => 'php://stderr', ], 'processors' => [ // Simple syntax... Monolog\Processor\MemoryUsageProcessor::class, // With options... [ 'processor' => Monolog\Processor\PsrLogMessageProcessor::class, 'with' => ['removeUsedContextFields' => true], ], ],],
透過工廠建立自訂通道
如果您想要定義一個完全自訂的通道,您可以在其中完全控制 Monolog 的實例化和設定,您可以在 config/logging.php
設定檔中指定 custom
驅動程式類型。您的設定應包含一個 via
選項,其中包含將被呼叫以建立 Monolog 實例的工廠類別的名稱。
'channels' => [ 'example-custom-channel' => [ 'driver' => 'custom', 'via' => App\Logging\CreateCustomLogger::class, ],],
一旦您設定了 custom
驅動程式通道,您就可以定義將建立 Monolog 實例的類別。這個類別只需要一個 __invoke
方法,該方法應傳回 Monolog 日誌記錄器實例。該方法將接收通道設定陣列作為其唯一參數。
<?php namespace App\Logging; use Monolog\Logger; class CreateCustomLogger{ /** * Create a custom Monolog instance. */ public function __invoke(array $config): Logger { return new Logger(/* ... */); }}
使用 Pail 追蹤記錄訊息
通常,您可能需要即時追蹤應用程式的日誌。例如,當除錯問題或監控應用程式日誌中特定類型的錯誤時。
Laravel Pail 是一個套件,可讓您直接從命令列輕鬆深入研究 Laravel 應用程式的日誌檔。與標準的 tail
命令不同,Pail 設計為可與任何日誌驅動程式(包括 Sentry 或 Flare)搭配使用。此外,Pail 提供了一組有用的篩選器,可協助您快速找到所需的內容。

安裝
首先,使用 Composer 套件管理器將 Pail 安裝到您的專案中。
composer require laravel/pail
使用方式
要開始追蹤日誌,請執行 pail
命令。
php artisan pail
要增加輸出的詳細程度並避免截斷(…),請使用 -v
選項。
php artisan pail -v
為了獲得最大的詳細程度並顯示例外堆疊追蹤,請使用 -vv
選項。
php artisan pail -vv
要停止追蹤日誌,請隨時按下 Ctrl+C
。
篩選記錄
--filter
您可以使用 --filter
選項來依其類型、檔案、訊息和堆疊追蹤內容篩選日誌。
php artisan pail --filter="QueryException"
--message
若要僅依訊息篩選日誌,您可以使用 --message
選項。
php artisan pail --message="User created"
--level
可以使用 --level
選項來依其日誌級別篩選日誌。
php artisan pail --level=error
--user
若要僅顯示在給定使用者通過驗證時寫入的日誌,您可以將使用者的 ID 提供給 --user
選項。
php artisan pail --user=1