Laravel

「Laravel」でログをJSON形式で保存する

「Laravel」のログ保存は、通常はテキスト形式となっております。
ただログの解析を行う場合に、JSON形式で読み取る必要のあるケースが存在します。
そこで「Laravel」が出力するログをJSON形式にする方法をまとめます。

「JSON」形式で保存するフォーマッターの実装

まずは「app/Logging/JsonLogFormatter.php」を作成します。
このケースでは通常のログの他に「Exception」発生時に内容をJSONで保存する事ができます。

<?php
namespace App\Logging;

use Monolog\Formatter\NormalizerFormatter;

/**
 * ログファイルをJSON形式で出力するための形式を定義する
 * Class JsonLogFormatter
 * @package App\Logging
 */
class JsonLogFormatter extends NormalizerFormatter
{
    /**
     * @var array
     */
    private $keys = [
        'exception',
    ];

    /**
     * JsonLogFormatter constructor.
     *
     * @param array|\Monolog\LogRecord $record
     *
     * @return ?string
     */
    public function format(array|\Monolog\LogRecord $record): ?string
    {
        $formatted = parent::format($record);

        // Set the default values
        $segments = [
            'datetime' => $formatted['datetime'],
            'level' => $formatted['level_name'],
            'message' => $formatted['message']
        ];

        // Set the context values
        foreach ($this->keys as $key)
        {
            if (isset($formatted['context'][$key]))
            {
                $segments[$key] = $formatted['context'][$key];
            }
        }

        // Set the extra values
        $segments['env'] = $formatted['channel'];
        $segments['extra'] = $formatted['extra'];

        // Return the JSON encoded string
        return json_encode($segments).PHP_EOL;
    }
}

次に「app/Logging/JsonLogApply.php」を実装します。

<?php

namespace App\Logging;

/**
 * ログファイルをJSON形式で出力するためのフォーマッター
 * Class JsonLogApply
 *
 * @package App\Logging
 */
class JsonLogApply
{
    public function __invoke($logging): void
    {
        $jsonFormatter = new JsonLogFormatter();
        foreach ($logging->getHandlers() as $handler)
        {
            $handler->setFormatter($jsonFormatter);
        }
    }
}

次に「config/logging.php」にある「channels」に以下の内容を追加します。

<?php

use Monolog\Handler\NullHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;

return [

    ...省略

    'channels' => [
        ...省略

        // For json log
        'json' => [
            'driver' => 'stack',
            'path' => storage_path('logs/' . env("LOG_FILE_NAME", "laravel.log")),
            'level' => env('LOG_LEVEL', 'debug'),
            'days' => 14,
            'channels' => ['bugsnag', 'daily'],
            'tap' => [App\Logging\JsonLogApply::class],
        ],
    ],
];

上記のファイルの修正が終わりましたら「.env」の「LOG_CHANNEL」を「json」に設定しましょう。

LOG_CHANNEL=json
LOG_SLACK_WEBHOOK_URL=
LOG_FILE_NAME=laravel.log

「Lumen」の場合

なお「Lumen」でプロジェクトを作成している場合、「config/logging.php」はデフォルトで存在しないため、「vendor/laravel/lumen-framework/config」に各種configファイルがあるので、それをコピーして使用しましょう。