Laravel のログにリクエストごとのIDを出す


システムに障害が発生してログを見た時に、いいタイミングで同時にリクエストが来てエラーも複数出ている際、これは同一リクエストで起こったエラーなのか、それともそれぞれ異なるリクエストで発生したエラーなのか分からなくなる現象がまれに起きます。特に外部連携系のAPIだと、リクエストが同一サーバーからくることが多いので、IPアドレスをログに出しても全部同じになってしまいます。そういった場合リクエストを区別するために、リクエストごとにUIDを振って出力する必要が出てきます。

Laravel はログ出力に monolog というライブラリを使用しており、 さらに monolog には UidProcessor という UID を振ってログ出力してくれる「プロセッサ」が既に用意されています。これを組み合わせることで、ログに UID が出力されるようになります。

ログ出力のカスタマイズ

Laravel のドキュメントを参考にソースを書きます。Laravel のドキュメントでは single チャネルに対して tap を設定していますが、デフォルト設定では single ではなく stack を使用するようになっています。また、 stack のデフォルト設定は daily なので、 daily に対して tap を指定します。(config/logging.php)

'stack' => [
    'driver' => 'stack',
    'channels' => ['daily'],
    'ignore_exceptions' => false,
],

// 初期状態ではここに single の設定がありますが省略

'daily' => [
    'driver' => 'daily',
    'path' => storage_path('logs/laravel.log'),
    'tap' => [App\Logging\CustomizeFormatter::class],
    'level' => 'debug',
    'days' => 14,
],

CustomizeFormatter の中身は以下のように書きます。 pushProcessor メソッドを使用し、UidProcessor を追加します。(app/Logging/CustomizeFormatter.php)

<?php

namespace App\Logging;

use Monolog\Processor\UidProcessor;

class CustomizeFormatter
{
    /**
     * Customize the given logger instance.
     *
     * @param  \Illuminate\Log\Logger  $logger
     * @return void
     */
    public function __invoke($logger)
    {
        $uidProcessor = new UidProcessor();
        foreach ($logger->getHandlers() as $handler) {
            $handler->pushProcessor($uidProcessor);
        }
    }
}

ログ出力確認用のコントローラを作成

ログ出力を確認するソースを書きます。出力結果だけ見たい場合はこの章は読み飛ばしてください。

まずはルーティング設定を書きます。HTML 返す気はないのでなんとなく API 配下に書きます。(routes/api.php)

<?php

Route::get('/', 'TestLogController@main');

つぎにコントローラーを書きます。 app/Http/Controllers/TestLogController.php

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;

class TestLogController extends Controller
{
    public function main(Request $request)
    {
        \Log::debug('1回目');
        \Log::debug('2回目');
        return new JsonResponse([]);
    }
}

ログ出力の確認

http://127.0.0.1:8000/api/に2回アクセスした結果がこちらです。後ろに JSON っぽい形で uid が出ています。

[2019-10-13 15:56:30] local.DEBUG: 1回目  {"uid":"0d5c3fa"}
[2019-10-13 15:56:30] local.DEBUG: 2回目  {"uid":"0d5c3fa"}
[2019-10-13 15:56:31] local.DEBUG: 1回目  {"uid":"d9060f4"}
[2019-10-13 15:56:31] local.DEBUG: 2回目  {"uid":"d9060f4"}

デフォルトのログフォーマットは Monolog\Formatter\LineFormatter に定義されている [%datetime%] %channel%.%level_name%: %message% %context% %extra%\nで、uid は extra に連想配列として格納されます。フォーマットを変更したい場合は、上記の CustomizeFormatterを以下のように変更することで可能です。

<?php

namespace App\Logging;

use Monolog\Formatter\LineFormatter; // 追加
use Monolog\Processor\UidProcessor;

class CustomizeFormatter
{
    /**
     * Customize the given logger instance.
     *
     * @param  \Illuminate\Log\Logger  $logger
     * @return void
     */
    public function __invoke($logger)
    {
        $uidProcessor = new UidProcessor();

        // extra.uid のようにドットを入れることで、連想配列の中身を指定できる
        // 第2引数以降に関して、 monolog と laravel のデフォルト値が異なるので laravel に合わせて設定している
        $formatter = new LineFormatter("[%datetime%] %channel%.%level_name% %extra.uid%: %message% %context%\n", 'Y-m-d H:i:s', true, true);

        foreach ($logger->getHandlers() as $handler) {
            $handler->pushProcessor($uidProcessor);
            $handler->setFormatter($formatter); // フォーマッターを差し替える
        }
    }
}

出力は以下のようになります。

[2019-10-13 16:13:01] local.DEBUG 154ff4d: 1回目 
[2019-10-13 16:13:01] local.DEBUG 154ff4d: 2回目 

UID の桁数はデフォルトだと7桁で出ますが、 UidProcessor のコンストラクタの第1引数で指定可能です。(1~32桁)

他のプロセッサの種類

このようにプロセッサを追加することで、いろいろな情報をログに追加することができます。すでにお気づきかと思いますが、monolog には UID 以外にも標準でプロセッサが用意されています。すでに Laravel 構築済みの場合は/vendor/monolog/monolog/src/Monolog/Processor/を見ると確認できます。

  • GitProcessor
  • HostnameProcessor
  • IntrospectionProcessor
  • MemoryPeakUsageProcessor
  • MemoryProcessor
  • MemoryUsageProcessor
  • MercurialProcessor
  • ProcessIdProcessor
  • PsrLogMessageProcessor
  • TagProcessor
  • UidProcessor
  • WebProcessor

この記事は UID がメインなので、他のプロセッサの紹介は割愛します。ソースきれいで分かりやすいので、気になる方は中身を見て確認してみてください。

環境情報

使用したものバージョン
PHP7.3.10
Laravel6.2.0
monolog2.0.0

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください