要約
Monolog\Formatter\JsonFormatter
を拡張したクラスを作り、それを使う。
メモ
前提
- アプリケーションは Laravel
- AWS の ECS で Cloudwatch Logs へ送信する
- Log Driver は awslogs
- エラーログに Stack trace も含めたい
この前提だと、デフォルトの LineFormatter では Stack trace が行ごとに分割されてしまう。
なので JSON で 1 行にフォーマットして出力する。
方法
- Laravel では Monolog の formatter が指定できるため、
Monolog\Formatter\JsonFormatter
を指定すれば良い(と思っていた) - しかし、JsonFormatter はデフォルトでは Stack trace を含めない(Monolog 2.1.1 時点)
- includeStacktraces メソッドを実行して切り替えることもできなさそう(Laravel 8.17.2 時点)
- しょうがないので JsonFormatter を拡張する
まず JsonFormatter を継承し、コンストラクタで includeStacktraces メソッドを実行するだけのクラスを作る。
# app/Logging/Formatter/CustomJsonFormatter.php
<?php
declare(strict_types=1);
namespace App\Logging\Formatter;
use Monolog\Formatter\JsonFormatter;
class CustomJsonFormatter extends JsonFormatter
{
/**
* @param int $batchMode
* @param bool $appendNewline
*/
public function __construct($batchMode = self::BATCH_MODE_JSON, $appendNewline = true)
{
parent::__construct($batchMode, $appendNewline);
$this->includeStacktraces();
}
}
次にログの設定で formatter に指定する。
# config/logging.php 抜粋
'channels' => [
'stderr' => [
'driver' => 'monolog',
'handler' => Monolog\Handler\StreamHandler::class,
'formatter' => App\Logging\Formatter\CustomJsonFormatter::class,
'with' => [
'stream' => 'php://stderr',
],
],
余談1
- Symfony では MonologBundle
を使えば解決らしい
- 良いなぁ
余談2
- Docker の log-driver オプションを使う方法もある
- が、どちらも失敗することがあった
- Stack trace が 50 行あったとして、
- 33 行め〜50 行め
- 4 行め〜32 行め
- 1 行め〜3 行め
- のように出力されることがある
- Stack trace が 50 行あったとして、
- たまたまフォーマットに一致した行が出てきたわけではない
- awslogs の文字数上限に引っかかっているわけでもない(謎)