はじめに
アプリケーション内で何が起こっているかをよりよく理解するために、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'],
],
チャネルの前提条件
単一および日次チャネルの設定
| 名前 | 説明 | デフォルト |
| --- | --- | --- |
| `````bubble````` | メッセージが処理された後、他のチャネルにバブルアップするかどうかを示します。 | `````true````` |
| `````locking````` | 書き込む前にログファイルをロックしようとします。 | `````false````` |
| `````permission````` | ログファイルの権限。 | `````0644````` |
さらに、`````daily`````チャネルの保持ポリシーは、`````LOG_DAILY_DAYS`````環境変数を介して、または`````days`````設定オプションを設定することによって構成できます。 <br><br>
| 名前 | 説明 | デフォルト |
| --- | --- | --- |
| `````days````` | 日次ログファイルが保持される日数。 | `````7````` |
<a name="configuring-the-papertrail-channel"></a>
#### Papertrailチャネルの設定
`````papertrail`````チャネルには、`````host`````および`````port`````設定オプションが必要です。これらは、`````PAPERTRAIL_URL`````および`````PAPERTRAIL_PORT`````環境変数を介して定義できます。これらの値は[Papertrail](https://help.papertrailapp.com/kb/configuration/configuring-centralized-logging-from-php-apps/#send-events-from-php-app)から取得できます。
<a name="configuring-the-slack-channel"></a>
#### Slackチャネルの設定
`````slack`````チャネルには、`````url`````設定オプションが必要です。この値は、`````LOG_SLACK_WEBHOOK_URL`````環境変数を介して定義できます。このURLは、Slackチームのために設定した[incoming webhook](https://slack.com/apps/A0F7XDUAZ-incoming-webhooks)のURLと一致する必要があります。
デフォルトでは、Slackは`````critical`````レベル以上のログのみを受信します。ただし、`````LOG_LEVEL`````環境変数を使用するか、Slackログチャネルの設定配列内の`````level`````設定オプションを変更することで、これを調整できます。
<a name="logging-deprecation-warnings"></a>
### 非推奨警告のログ記録
PHP、Laravel、および他のライブラリは、しばしばユーザーに対して、いくつかの機能が非推奨であり、将来のバージョンで削除されることを通知します。これらの非推奨警告をログに記録したい場合は、`````deprecations`````ログチャネルを`````LOG_DEPRECATIONS_CHANNEL`````環境変数を使用して指定するか、アプリケーションの`````config/logging.php`````設定ファイル内で指定できます:
``````php
'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
オプションを介して他の2つのチャネルを集約していることに注意してください:syslog
およびslack
。したがって、メッセージをログに記録する際には、これらのチャネルの両方がメッセージをログに記録する機会を持ちます。ただし、以下で見るように、これらのチャネルが実際にメッセージをログに記録するかどうかは、メッセージの重大度/「レベル」によって決まる場合があります。
ログレベル
上記の例でlevel
設定オプションがsyslog
およびslack
チャネル設定に存在することに注意してください。このオプションは、メッセージがチャネルによってログに記録されるために必要な最小「レベル」を決定します。Laravelのロギングサービスを支えるMonologは、RFC 5424仕様で定義されたすべてのログレベルを提供します。重大度の降順で、これらのログレベルは次のとおりです: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
ファサードを使用します。前述のように、ロガーはRFC 5424仕様で定義された8つのロギングレベルを提供します: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
]);
// ...
}
}
キューに入れられたジョブを処理する際にログコンテキストを共有する必要がある場合は、ジョブミドルウェアを利用できます。
特定のチャネルへの書き込み
時には、アプリケーションのデフォルトチャネル以外のチャネルにメッセージをログに記録したい場合があります。channel
メソッドをLog
ファサードで使用して、設定ファイルで定義された任意のチャネルにログを記録できます:
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
ドライバーを使用して簡単に作成できます。
``````php
'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が提供する既存のプロセッサーを使用できます。
``````php
'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のインスタンス化と構成を完全に制御できる完全にカスタムなチャネルを定義したい場合は、custom
ドライバータイプをconfig/logging.php
設定ファイルに指定できます。設定には、Monologインスタンスを作成するために呼び出されるファクトリークラスの名前を含むvia
オプションを含める必要があります:
'channels' => [
'example-custom-channel' => [
'driver' => 'custom',
'via' => App\Logging\CreateCustomLogger::class,
],
],
``````php
<?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は、探しているものを迅速に見つけるのに役立つ便利なフィルターのセットを提供します。
インストール
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
ログのフィルタリング
—filter
``````bash
php artisan pail --filter="QueryException"
`
—message
メッセージのみでログをフィルタリングするには、--message
オプションを使用します:
php artisan pail --message="User created"
—level
``````bash
php artisan pail --level=error
`
—user
特定のユーザーが認証されている間に書き込まれたログのみを表示するには、--user
オプションにユーザーのIDを提供します:
php artisan pail --user=1