跳至內容

記錄

簡介

為了幫助您深入了解應用程式內部的運作情況,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 驅動程式。
lightbulb

請查看關於進階通道自訂的文件,以深入了解 monologcustom 驅動程式。

設定通道名稱

依預設,Monolog 會使用與目前環境相符的「通道名稱」來例項化,例如 productionlocal。若要變更此值,您可以將 name 選項新增至通道的設定中

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

通道先決條件

設定 Single 和 Daily 通道

singledaily 通道有三個可選的設定選項:bubblepermissionlocking

名稱 描述 預設值
bubble 指示在處理訊息後,是否應將訊息向上傳遞到其他通道。 true
locking 嘗試在寫入記錄檔之前鎖定它。 false
permission 記錄檔的權限。 0644

此外,daily 通道的保留原則可以透過 LOG_DAILY_DAYS 環境變數或設定 days 設定選項來設定。

名稱 描述 預設值
days 應該保留每日記錄檔的天數。 14

設定 Papertrail 通道

papertrail 通道需要 hostport 設定選項。這些選項可以透過 PAPERTRAIL_URLPAPERTRAIL_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 選項匯總了另外兩個通道:syslogslack。因此,在記錄訊息時,這兩個通道都有機會記錄訊息。但是,如下所示,這些通道是否實際記錄訊息可能會由訊息的嚴重性 /「級別」來決定。

記錄級別

請注意以上範例中 syslogslack 通道配置中的 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
]);
 
// ...
}
}
lightbulb

如果您需要在處理佇列任務時共享日誌關聯資訊,您可以使用任務中介軟體

寫入特定通道

有時您可能希望將訊息記錄到應用程式預設通道以外的其他通道。您可以使用 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%'
));
}
}
}
lightbulb

您所有的「點擊」類別都由服務容器解析,因此它們需要的任何建構子相依性都會自動注入。

建立 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 將用作預設格式器。但是,您可以使用 formatterformatter_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 提供了一組有用的篩選器,可協助您快速找到所需的內容。

安裝

exclamation

Laravel Pail 需要 PHP 8.2+PCNTL 擴充功能。

首先,使用 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