はじめに

アプリケーション内で何が起こっているかをよりよく理解するために、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は現在の環境に一致する「チャネル名」でインスタンス化されます。たとえば、productionlocalなどです。この値を変更するには、チャネルの設定にnameオプションを追加できます:

  1. 'stack' => [
  2. 'driver' => 'stack',
  3. 'name' => 'channel-name',
  4. 'channels' => ['single', 'slack'],
  5. ],

チャネルの前提条件

単一および日次チャネルの設定

  1. | 名前 | 説明 | デフォルト |
  2. | --- | --- | --- |
  3. | `````bubble````` | メッセージが処理された後、他のチャネルにバブルアップするかどうかを示します。 | `````true````` |
  4. | `````locking````` | 書き込む前にログファイルをロックしようとします。 | `````false````` |
  5. | `````permission````` | ログファイルの権限。 | `````0644````` |
  6. さらに、`````daily`````チャネルの保持ポリシーは、`````LOG_DAILY_DAYS`````環境変数を介して、または`````days`````設定オプションを設定することによって構成できます。 <br><br>
  7. | 名前 | 説明 | デフォルト |
  8. | --- | --- | --- |
  9. | `````days````` | 日次ログファイルが保持される日数。 | `````7````` |
  10. <a name="configuring-the-papertrail-channel"></a>
  11. #### Papertrailチャネルの設定
  12. `````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)から取得できます。
  13. <a name="configuring-the-slack-channel"></a>
  14. #### Slackチャネルの設定
  15. `````slack`````チャネルには、`````url`````設定オプションが必要です。この値は、`````LOG_SLACK_WEBHOOK_URL`````環境変数を介して定義できます。このURLは、Slackチームのために設定した[incoming webhook](https://slack.com/apps/A0F7XDUAZ-incoming-webhooks)のURLと一致する必要があります。
  16. デフォルトでは、Slack`````critical`````レベル以上のログのみを受信します。ただし、`````LOG_LEVEL`````環境変数を使用するか、Slackログチャネルの設定配列内の`````level`````設定オプションを変更することで、これを調整できます。
  17. <a name="logging-deprecation-warnings"></a>
  18. ### 非推奨警告のログ記録
  19. PHPLaravel、および他のライブラリは、しばしばユーザーに対して、いくつかの機能が非推奨であり、将来のバージョンで削除されることを通知します。これらの非推奨警告をログに記録したい場合は、`````deprecations`````ログチャネルを`````LOG_DEPRECATIONS_CHANNEL`````環境変数を使用して指定するか、アプリケーションの`````config/logging.php`````設定ファイル内で指定できます:
  20. ``````php
  21. 'deprecations' => [
  22. 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
  23. 'trace' => env('LOG_DEPRECATIONS_TRACE', false),
  24. ],
  25. 'channels' => [
  26. // ...
  27. ]
  28. `

または、deprecationsという名前のログチャネルを定義することもできます。この名前のログチャネルが存在する場合、常に非推奨をログに記録するために使用されます:

  1. 'channels' => [
  2. 'deprecations' => [
  3. 'driver' => 'single',
  4. 'path' => storage_path('logs/php-deprecation-warnings.log'),
  5. ],
  6. ],

ログスタックの構築

前述のように、stackドライバーを使用すると、複数のチャネルを単一のログチャネルに組み合わせることができます。ログスタックの使用方法を示すために、実際のアプリケーションで見られる可能性のある設定の例を見てみましょう:

  1. 'channels' => [
  2. 'stack' => [
  3. 'driver' => 'stack',
  4. 'channels' => ['syslog', 'slack'],
  5. 'ignore_exceptions' => false,
  6. ],
  7. 'syslog' => [
  8. 'driver' => 'syslog',
  9. 'level' => env('LOG_LEVEL', 'debug'),
  10. 'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER),
  11. 'replace_placeholders' => true,
  12. ],
  13. 'slack' => [
  14. 'driver' => 'slack',
  15. 'url' => env('LOG_SLACK_WEBHOOK_URL'),
  16. 'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'),
  17. 'emoji' => env('LOG_SLACK_EMOJI', ':boom:'),
  18. 'level' => env('LOG_LEVEL', 'critical'),
  19. 'replace_placeholders' => true,
  20. ],
  21. ],

この設定を分解してみましょう。まず、stackチャネルがchannelsオプションを介して他の2つのチャネルを集約していることに注意してください:syslogおよびslack。したがって、メッセージをログに記録する際には、これらのチャネルの両方がメッセージをログに記録する機会を持ちます。ただし、以下で見るように、これらのチャネルが実際にメッセージをログに記録するかどうかは、メッセージの重大度/「レベル」によって決まる場合があります。

ログレベル

上記の例でlevel設定オプションがsyslogおよびslackチャネル設定に存在することに注意してください。このオプションは、メッセージがチャネルによってログに記録されるために必要な最小「レベル」を決定します。Laravelのロギングサービスを支えるMonologは、RFC 5424仕様で定義されたすべてのログレベルを提供します。重大度の降順で、これらのログレベルは次のとおりです:emergencyalertcriticalerrorwarningnoticeinfo、およびdebug

したがって、debugメソッドを使用してメッセージをログに記録すると仮定します:

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

設定に基づいて、syslogチャネルはメッセージをシステムログに書き込みます。ただし、エラーメッセージはcritical以上ではないため、Slackには送信されません。ただし、emergencyメッセージをログに記録すると、emergencyレベルが両方のチャネルの最小レベル閾値を超えているため、システムログとSlackの両方に送信されます:

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

ログメッセージの記録

ログに情報を書き込むには、Log ファサードを使用します。前述のように、ロガーはRFC 5424仕様で定義された8つのロギングレベルを提供します:emergencyalertcriticalerrorwarningnoticeinfoおよびdebug

  1. use Illuminate\Support\Facades\Log;
  2. Log::emergency($message);
  3. Log::alert($message);
  4. Log::critical($message);
  5. Log::error($message);
  6. Log::warning($message);
  7. Log::notice($message);
  8. Log::info($message);
  9. Log::debug($message);

これらのメソッドのいずれかを呼び出して、対応するレベルのメッセージをログに記録できます。デフォルトでは、メッセージはlogging設定ファイルで構成されたデフォルトのログチャネルに書き込まれます:

  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\Http\Controllers\Controller;
  4. use App\Models\User;
  5. use Illuminate\Support\Facades\Log;
  6. use Illuminate\View\View;
  7. class UserController extends Controller
  8. {
  9. /**
  10. * Show the profile for the given user.
  11. */
  12. public function show(string $id): View
  13. {
  14. Log::info('Showing the user profile for user: {id}', ['id' => $id]);
  15. return view('user.profile', [
  16. 'user' => User::findOrFail($id)
  17. ]);
  18. }
  19. }

コンテキスト情報

コンテキストデータの配列をログメソッドに渡すことができます。このコンテキストデータは、ログメッセージと共にフォーマットされて表示されます:

  1. use Illuminate\Support\Facades\Log;
  2. Log::info('User {id} failed to login.', ['id' => $user->id]);

時折、特定のチャネルのすべての後続のログエントリに含めるべきコンテキスト情報を指定したい場合があります。たとえば、アプリケーションへの各リクエストに関連付けられたリクエストIDをログに記録したい場合があります。これを実現するには、LogファサードのwithContextメソッドを呼び出すことができます:

  1. <?php
  2. namespace App\Http\Middleware;
  3. use Closure;
  4. use Illuminate\Http\Request;
  5. use Illuminate\Support\Facades\Log;
  6. use Illuminate\Support\Str;
  7. use Symfony\Component\HttpFoundation\Response;
  8. class AssignRequestId
  9. {
  10. /**
  11. * Handle an incoming request.
  12. *
  13. * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
  14. */
  15. public function handle(Request $request, Closure $next): Response
  16. {
  17. $requestId = (string) Str::uuid();
  18. Log::withContext([
  19. 'request-id' => $requestId
  20. ]);
  21. $response = $next($request);
  22. $response->headers->set('Request-Id', $requestId);
  23. return $response;
  24. }
  25. }

すべてのロギングチャネルでコンテキスト情報を共有したい場合は、Log::shareContext()メソッドを呼び出すことができます。このメソッドは、すべての作成されたチャネルおよびその後に作成されるチャネルにコンテキスト情報を提供します:

  1. <?php
  2. namespace App\Http\Middleware;
  3. use Closure;
  4. use Illuminate\Http\Request;
  5. use Illuminate\Support\Facades\Log;
  6. use Illuminate\Support\Str;
  7. use Symfony\Component\HttpFoundation\Response;
  8. class AssignRequestId
  9. {
  10. /**
  11. * Handle an incoming request.
  12. *
  13. * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
  14. */
  15. public function handle(Request $request, Closure $next): Response
  16. {
  17. $requestId = (string) Str::uuid();
  18. Log::shareContext([
  19. 'request-id' => $requestId
  20. ]);
  21. // ...
  22. }
  23. }

キューに入れられたジョブを処理する際にログコンテキストを共有する必要がある場合は、ジョブミドルウェアを利用できます。

特定のチャネルへの書き込み

時には、アプリケーションのデフォルトチャネル以外のチャネルにメッセージをログに記録したい場合があります。channelメソッドをLogファサードで使用して、設定ファイルで定義された任意のチャネルにログを記録できます:

  1. use Illuminate\Support\Facades\Log;
  2. Log::channel('slack')->info('Something happened!');

複数のチャネルで構成されるオンデマンドロギングスタックを作成したい場合は、stackメソッドを使用できます:

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

オンデマンドチャネル

アプリケーションのlogging設定ファイルにその設定が存在しない状態で、ランタイムに設定を提供することによってオンデマンドチャネルを作成することも可能です。これを実現するには、Logファサードのbuildメソッドに設定配列を渡すことができます:

  1. use Illuminate\Support\Facades\Log;
  2. Log::build([
  3. 'driver' => 'single',
  4. 'path' => storage_path('logs/custom.log'),
  5. ])->info('Something happened!');

オンデマンドロギングスタックにオンデマンドチャネルを含めたい場合は、stackメソッドに渡される配列にオンデマンドチャネルインスタンスを含めることで実現できます:

  1. use Illuminate\Support\Facades\Log;
  2. $channel = Log::build([
  3. 'driver' => 'single',
  4. 'path' => storage_path('logs/custom.log'),
  5. ]);
  6. Log::stack(['slack', $channel])->info('Something happened!');

Monologチャネルのカスタマイズ

チャネルのためのMonologのカスタマイズ

時には、既存のチャネルに対してMonologがどのように構成されるかを完全に制御する必要がある場合があります。たとえば、Laravelの組み込みsingleチャネルのためにカスタムMonolog FormatterInterface実装を構成したい場合があります。

始めるには、チャネルの設定にtap配列を定義します。tap配列には、Monologインスタンスが作成された後にカスタマイズ(または「タップ」)する機会を持つクラスのリストを含める必要があります。これらのクラスを配置するための慣習的な場所はないため、これらのクラスを含むディレクトリをアプリケーション内に自由に作成できます:

  1. 'single' => [
  2. 'driver' => 'single',
  3. 'tap' => [App\Logging\CustomizeFormatter::class],
  4. 'path' => storage_path('logs/laravel.log'),
  5. 'level' => env('LOG_LEVEL', 'debug'),
  6. 'replace_placeholders' => true,
  7. ],

チャネルのtapオプションを構成したら、Monologインスタンスをカスタマイズするクラスを定義する準備が整いました。このクラスには、invokeという単一のメソッドが必要で、Illuminate\Log\Loggerインスタンスを受け取ります。Illuminate\Log\Loggerインスタンスは、すべてのメソッド呼び出しを基盤となるMonologインスタンスにプロキシします:

  1. <?php
  2. namespace App\Logging;
  3. use Illuminate\Log\Logger;
  4. use Monolog\Formatter\LineFormatter;
  5. class CustomizeFormatter
  6. {
  7. /**
  8. * Customize the given logger instance.
  9. */
  10. public function __invoke(Logger $logger): void
  11. {
  12. foreach ($logger->getHandlers() as $handler) {
  13. $handler->setFormatter(new LineFormatter(
  14. '[%datetime%] %channel%.%level_name%: %message% %context% %extra%'
  15. ));
  16. }
  17. }
  18. }

すべての「タップ」クラスは、サービスコンテナによって解決されるため、必要なコンストラクタ依存関係は自動的に注入されます。

Monologハンドラーチャネルの作成

Monologにはさまざまな利用可能なハンドラーがあり、Laravelはそれぞれに対して組み込みのチャネルを含んでいません。場合によっては、対応するLaravelログドライバーを持たない特定のMonologハンドラーのインスタンスであるカスタムチャネルを作成したい場合があります。これらのチャネルは、monologドライバーを使用して簡単に作成できます。

  1. ``````php
  2. 'logentries' => [
  3. 'driver' => 'monolog',
  4. 'handler' => Monolog\Handler\SyslogUdpHandler::class,
  5. 'with' => [
  6. 'host' => 'my.logentries.internal.datahubhost.company.com',
  7. 'port' => '10000',
  8. ],
  9. ],
  10. `

Monologフォーマッター

monologドライバーを使用する場合、Monolog LineFormatterがデフォルトのフォーマッターとして使用されます。ただし、formatterおよびformatter_with設定オプションを使用して、ハンドラーに渡されるフォーマッターのタイプをカスタマイズできます:

  1. 'browser' => [
  2. 'driver' => 'monolog',
  3. 'handler' => Monolog\Handler\BrowserConsoleHandler::class,
  4. 'formatter' => Monolog\Formatter\HtmlFormatter::class,
  5. 'formatter_with' => [
  6. 'dateFormat' => 'Y-m-d',
  7. ],
  8. ],

Monologハンドラーが独自のフォーマッターを提供できる場合は、formatter設定オプションの値をdefaultに設定できます:

  1. 'newrelic' => [
  2. 'driver' => 'monolog',
  3. 'handler' => Monolog\Handler\NewRelicHandler::class,
  4. 'formatter' => 'default',
  5. ],

Monologプロセッサー

Monologは、メッセージをログに記録する前に処理することもできます。独自のプロセッサーを作成するか、Monologが提供する既存のプロセッサーを使用できます。

  1. ``````php
  2. 'memory' => [
  3. 'driver' => 'monolog',
  4. 'handler' => Monolog\Handler\StreamHandler::class,
  5. 'with' => [
  6. 'stream' => 'php://stderr',
  7. ],
  8. 'processors' => [
  9. // Simple syntax...
  10. Monolog\Processor\MemoryUsageProcessor::class,
  11. // With options...
  12. [
  13. 'processor' => Monolog\Processor\PsrLogMessageProcessor::class,
  14. 'with' => ['removeUsedContextFields' => true],
  15. ],
  16. ],
  17. ],
  18. `

ファクトリーを介してカスタムチャネルを作成する

Monologのインスタンス化と構成を完全に制御できる完全にカスタムなチャネルを定義したい場合は、customドライバータイプをconfig/logging.php設定ファイルに指定できます。設定には、Monologインスタンスを作成するために呼び出されるファクトリークラスの名前を含むviaオプションを含める必要があります:

  1. 'channels' => [
  2. 'example-custom-channel' => [
  3. 'driver' => 'custom',
  4. 'via' => App\Logging\CreateCustomLogger::class,
  5. ],
  6. ],
  1. ``````php
  2. <?php
  3. namespace App\Logging;
  4. use Monolog\Logger;
  5. class CreateCustomLogger
  6. {
  7. /**
  8. * Create a custom Monolog instance.
  9. */
  10. public function __invoke(array $config): Logger
  11. {
  12. return new Logger(/* ... */);
  13. }
  14. }
  15. `

Pailを使用したログメッセージの追跡

アプリケーションのログをリアルタイムで追跡する必要がある場合がよくあります。たとえば、問題をデバッグしたり、特定の種類のエラーに対してアプリケーションのログを監視したりする場合です。

Laravel Pailは、コマンドラインから直接Laravelアプリケーションのログファイルに簡単にアクセスできるパッケージです。標準のtailコマンドとは異なり、PailはSentryやFlareを含む任意のログドライバーで動作するように設計されています。さらに、Pailは、探しているものを迅速に見つけるのに役立つ便利なフィルターのセットを提供します。
ロギング(Logging) - img1

インストール

Laravel PailはPHP 8.2+およびPCNTL拡張を必要とします。

始めるには、Composerパッケージマネージャーを使用してプロジェクトにPailをインストールします:

  1. composer require laravel/pail

使用法

ログの追跡を開始するには、pailコマンドを実行します:

  1. php artisan pail

出力の冗長性を高め、切り捨てを避けるには(…)、-vオプションを使用します:

  1. php artisan pail -v

最大の冗長性を確保し、例外スタックトレースを表示するには、-vvオプションを使用します:

  1. php artisan pail -vv

ログの追跡を停止するには、いつでもCtrl+Cを押します。

ログのフィルタリング

—filter

  1. ``````bash
  2. php artisan pail --filter="QueryException"
  3. `

—message

メッセージのみでログをフィルタリングするには、--messageオプションを使用します:

  1. php artisan pail --message="User created"

—level

  1. ``````bash
  2. php artisan pail --level=error
  3. `

—user

特定のユーザーが認証されている間に書き込まれたログのみを表示するには、--userオプションにユーザーのIDを提供します:

  1. php artisan pail --user=1