記錄
簡介
為了幫助您更深入了解應用程式內部發生的事情,Laravel 提供了強大的記錄服務,讓您可以將訊息記錄到檔案、系統錯誤記錄,甚至透過 Slack 通知整個團隊。
Laravel 的記錄基於「通道」。每個通道代表一種特定的記錄資訊方式。例如,single
通道將記錄檔寫入單一記錄檔,而 slack
通道則將記錄訊息發送到 Slack。根據嚴重性,記錄訊息可能會被寫入多個通道。
在幕後,Laravel 使用 Monolog 函式庫,提供各種強大的記錄處理程序支援。Laravel 讓您輕鬆配置這些處理程序,讓您可以混合搭配它們以自訂應用程式的記錄處理。
組態設定
控制應用程式記錄行為的所有組態選項都存放在 config/logging.php
組態檔案中。這個檔案允許您配置應用程式的記錄通道,請務必查看每個可用通道及其選項。以下是一些常見選項的概述。
預設情況下,Laravel 在記錄訊息時會使用 stack
通道。stack
通道用於將多個日誌通道聚合到單一通道中。有關構建堆疊的更多資訊,請查看下面的文件。
可用的通道驅動程式
每個日誌通道都由一個"驅動程式"提供動力。該驅動程式決定了日誌訊息實際記錄的方式和位置。以下是每個 Laravel 應用程式中都可用的日誌通道驅動程式。大多數這些驅動程式的條目已經存在於您應用程式的 config/logging.php
配置檔中,請務必查看此檔案以熟悉其內容:
[!NOTE]
查看進階通道自訂的文件,以了解更多關於monolog
和custom
驅動程式的資訊。
配置通道名稱
預設情況下,Monolog 使用與當前環境相符的"通道名稱"來實例化,例如 production
或 local
。若要更改此值,您可以在通道的配置中添加一個 name
選項:
'stack' => [
'driver' => 'stack',
'name' => 'channel-name',
'channels' => ['single', 'slack'],
],
頻道先決條件
配置單一和每日頻道
single
和 daily
頻道有三個可選的配置選項:bubble
、permission
和 locking
。
此外,daily
頻道的保留策略可以通過 LOG_DAILY_DAYS
環境變數或設置 days
配置選項來進行配置。
配置 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'], // [tl! add]
'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('一則資訊訊息。');
根據我們的配置,syslog
通道將把訊息寫入系統日誌;然而,由於錯誤訊息不是 critical
或更高級別,它將不會被發送到 Slack。然而,如果我們記錄一個 emergency
訊息,它將被同時發送到系統日誌和 Slack,因為 emergency
級別高於我們設定的兩個通道的最低級別閾值:
Log::emergency('系統已經崩潰!');
寫入日誌訊息
您可以使用 Log
facade 將資訊寫入日誌。如前所述,記錄器提供了 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('用戶 {id} 登入失敗。', ['id' => $user->id]);
有時,您可能希望指定一些應該包含在特定通道中所有後續日誌項目中的上下文資訊。例如,您可能希望記錄與應用程序的每個傳入請求相關聯的請求 ID。為了實現這一點,您可以調用 Log
facade 的 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
]);
// ...
}
}
[!NOTE]
如果您需要在處理排隊的工作時共享日誌上下文,您可以利用 工作中介層。
寫入到特定頻道
有時您可能希望將消息記錄到應用程序的默認頻道以外的頻道。您可以使用 Log
門面上的 channel
方法來檢索並記錄到配置文件中定義的任何頻道:
use Illuminate\Support\Facades\Log;
Log::channel('slack')->info('發生了某事!');
如果您想要創建由多個頻道組成的即時記錄堆棧,您可以使用 stack
方法:
Log::stack(['single', 'slack'])->info('發生了某事!');
即時頻道
還可以通過在運行時提供配置而無需將該配置存在於應用程序的 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 實例後自定義(或“tap”進入)該實例。這些類別應放置在哪裡沒有傳統的位置,因此您可以自由地在應用程序中創建一個目錄來包含這些類別:
'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%'
));
}
}
}
[!NOTE]
所有您的 "tap" 類別都是由 服務容器 解析的,因此它們所需的任何建構子依賴將自動被注入。
建立 Monolog 處理程序頻道
Monolog 有各種可用的處理程序,而 Laravel 並未為每個處理程序提供內建的頻道。在某些情況下,您可能希望創建一個自定義頻道,這僅僅是一個特定 Monolog 處理程序的實例,而該處理程序沒有對應的 Laravel 日誌驅動程式。這些頻道可以輕鬆地使用 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