ロギング¶
はじめに¶
アプリケーション内で何が起こっているかを詳しく知るために、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ドライバ。 |
Note
高度なチャンネルカスタマイズのドキュメントを参照して、monolog
およびcustom
ドライバの詳細を学んでください。
チャンネル名の設定¶
デフォルトでは、Monologは現在の環境に一致する「チャンネル名」(例:production
またはlocal
)でインスタンス化されます。この値を変更するには、チャンネルの設定にname
オプションを追加できます。
'stack' => [
'driver' => 'stack',
'name' => 'channel-name',
'channels' => ['single', 'slack'],
],
チャンネルの前提条件¶
SingleおよびDailyチャンネルの設定¶
single
およびdaily
チャンネルには、3つのオプションの設定オプションがあります:bubble
、permission
、およびlocking
。
名前 | 説明 | デフォルト |
---|---|---|
bubble |
メッセージが処理された後、他のチャンネルにバブルアップするかどうかを示します。 | true |
locking |
ログファイルに書き込む前にロックを試みます。 | false |
permission |
ログファイルのパーミッション。 | 0644 |
さらに、daily
チャンネルの保持ポリシーは、LOG_DAILY_DAYS
環境変数またはdays
設定オプションを介して設定できます。
名前 | 説明 | デフォルト |
---|---|---|
days |
日次ログファイルを保持する日数。 | 7 |
Papertrailチャンネルの設定¶
papertrail
チャンネルには、host
およびport
設定オプションが必要です。これらは、PAPERTRAIL_URL
およびPAPERTRAIL_PORT
環境変数を介して定義できます。これらの値は、Papertrailから取得できます。
Slackチャンネルの設定¶
slack
チャンネルには、url
設定オプションが必要です。この値は、LOG_SLACK_WEBHOOK_URL
環境変数を介して定義できます。このURLは、Slackチーム用に設定したインカミングウェブフックの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
オプションを介して他の2つのチャンネル(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
メッセージをログに記録する場合、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
{
/**
* 指定されたユーザーのプロフィールを表示します。
*/
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
{
/**
* 受信リクエストを処理します。
*
* @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
{
/**
* 受信リクエストを処理します。
*
* @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('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インスタンスをカスタマイズするクラスを定義する準備が整いました。このクラスには、Illuminate\Log\Logger
インスタンスを受け取る__invoke
メソッドが1つ必要です。Illuminate\Log\Logger
インスタンスは、基礎となるMonologインスタンスへのすべてのメソッド呼び出しをプロキシします:
<?php
namespace App\Logging;
use Illuminate\Log\Logger;
use Monolog\Formatter\LineFormatter;
class CustomizeFormatter
{
/**
* 指定されたロガーインスタンスをカスタマイズします。
*/
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ハンドラのインスタンスであるカスタムチャンネルを作成したい場合があります。これらのチャンネルは、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' => [
// シンプルな構文...
Monolog\Processor\MemoryUsageProcessor::class,
// オプション付き...
[
'processor' => Monolog\Processor\PsrLogMessageProcessor::class,
'with' => ['removeUsedContextFields' => true],
],
],
],
ファクトリを介したカスタムチャンネルの作成¶
Monologのインスタンス化と設定を完全に制御できる完全にカスタムなチャンネルを定義したい場合は、config/logging.php
設定ファイルでcustom
ドライバタイプを指定できます。設定には、Monologインスタンスを作成するために呼び出されるファクトリクラスの名前を含むvia
オプションを含める必要があります。
'channels' => [
'example-custom-channel' => [
'driver' => 'custom',
'via' => App\Logging\CreateCustomLogger::class,
],
],
custom
ドライバチャンネルを設定したら、Monologインスタンスを作成するクラスを定義する準備が整いました。このクラスには、Monologロガーインスタンスを返す必要がある単一の__invoke
メソッドが必要です。このメソッドは、チャンネル設定配列を唯一の引数として受け取ります。
<?php
namespace App\Logging;
use Monolog\Logger;
class CreateCustomLogger
{
/**
* カスタムMonologインスタンスを作成する。
*/
public function __invoke(array $config): Logger
{
return new Logger(/* ... */);
}
}
Pailを使用したログメッセージのテイル¶
アプリケーションのログをリアルタイムでテイルする必要がある場合があります。例えば、問題のデバッグや、特定の種類のエラーのアプリケーションログの監視などです。
Laravel Pailは、コマンドラインから直接Laravelアプリケーションのログファイルに簡単にアクセスできるようにするパッケージです。標準のtail
コマンドとは異なり、PailはSentryやFlareを含む任意のログドライバで動作するように設計されています。さらに、Pailは、探しているものをすばやく見つけるのに役立つ一連の便利なフィルタを提供します。
インストール¶
始めるには、Composerパッケージマネージャを使用してPailをプロジェクトにインストールします。
使用方法¶
ログのテイルを開始するには、pail
コマンドを実行します。
出力の冗長性を上げ、切り捨て(…)を避けるには、-v
オプションを使用します。
最大の冗長性と例外スタックトレースを表示するには、-vv
オプションを使用します。
ログのテイルを停止するには、いつでもCtrl+C
を押します。
ログのフィルタリング¶
--filter
¶
ログをタイプ、ファイル、メッセージ、スタックトレースの内容でフィルタリングするには、--filter
オプションを使用します。
--message
¶
ログをメッセージのみでフィルタリングするには、--message
オプションを使用します。
--level
¶
ログをログレベルでフィルタリングするには、--level
オプションを使用します。
--user
¶
特定のユーザーが認証されている間に書き込まれたログのみを表示するには、ユーザーのIDを--user
オプションに指定します。