はじめに
こんにちは。今回は表題通り、Laravel5.8でのログの扱い方です。
わざわざバージョンを記載しているのは、2019年7月現在のLTSである5.5と5.6以降で大きな変更があったためです。本記事の内容は5.5以前には適用できない可能性がありますので、ご注意ください。
環境
- PHP 7.3.6
- Laravel 5.8.28
Monologについて
Laravelのログ機能はMonologのラッパーであり、これは5.8になっても同じです。変わったのはログの呼び出し方や設定方法のようです(私は5.8からLaravelを使い始めたので、5.5以前の書き方は把握していません…)。
なおMonolog自体はLaravelとは本来関係ないパッケージのため、Laravel公式のドキュメントよりはMonolog単体で調べた方が、まとまった情報を得ることができると思います。
コード上で設定する方法
では早速Laravelでの使い方を見ていきます。簡単かつMonologに不慣れな人でもパッと見で分かりやすいのは、コード上で全て設定してしまう方法です。
以下は「ユーザー登録時にLaravel標準とは別にログを出力したい」という意図のコードです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | useMonolog\Formatter\LineFormatter; useMonolog\Handler\RotatingFileHandler; useMonolog\Logger; protectedfunctioncreate(array$data) { $user=User::create([ 'name'=>$data['name'], 'email'=>$data['email'], 'password'=>Hash::make($data['password']), ]); $log_path=storage_path('logs/user-register.log'); $days=90; $log_level='debug'; $bubble=true; $filePermission=0777; $handler=newRotatingFileHandler($log_path,$days,$log_level,$bubble,$filePermission); $formatter=newLineFormatter(null,null,true,true); $handler->setFormatter($formatter); $logger=newLogger('user-register'); $logger->pushHandler($handler); $logger->info(sprintf('ユーザーID:%sが登録されました。',$user->id)); return$user; } |
- $log_path: ログのファイルパスです。アプリケーションのどこに設置してもいいのですが、ヘルパ関数の
storage_path()
を使ってstorage/logs
以下を指定するのが慣例です。 - $days: ログの保存日数です。この場合はログが90日間保存され、その後は古い順に削除されます。「0」を指定すると無期限で保存されます。
- $log_level: ログレベルはPHPのデファクトであるPSR-3に準拠しています。https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#5-psrlogloglevel
- $bubble: 他のハンドラに処理続行させるかのフラグです。Laravelでは…というかMonologでは複数のログハンドラを同時に起動してログ出力ができます。イメージ的には、バリデーションでエラー検知時にバリデーションを継続させるのに近いと思います。
- $filePermission: これは読んで字の如く、ログファイルのパーミッションです。
chmod
と同じように指定できます。 - RotatingFileHandler: Monologが最初から用意しているログハンドラで、ログファイルを日毎にローテーションしてくれます。他にも標準出力にログを吐き出す
StreamHandler
、Slackに手軽にPOSTできるSlackHandler
など、様々なハンドラがあり、実体はvendor/monolog/monolog/src/Monolog/Handler
以下にあります。 - LineFormatter: ログ文面のフォーマットを指定します。何も指定しない場合は
const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n";
というフォーマットに沿って出力されます。
ControllerやServiceに書いてしまうのはあまりスマートではなく、コードの肥大化も招きます。trait化したり、設定値を.env
やconfig
に追い出すことで可読性を保てるのではないでしょうか。
上記のコードでstorage/logs/user-register-[YYYY-MM-DD].log
が生成され、以下のようなログが出力されます。storage/logs/laravel-[YYYY-MM-DD].log
はLaravelデフォルトのログで、config/logging.php
の設定に沿って出力されます(後述)。
config/logging.phpで設定する方法
5.6以降で追加された設定ファイルで、公式ドキュメントを見る限り、恐らくこちらが推奨の方法だと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 'default'=>env('LOG_CHANNEL','stack'), (中略) 'channels'=>[ 'stack'=>[ 'driver'=>'stack', 'channels'=>['daily'], 'ignore_exceptions'=>false, ], 'single'=>[ 'driver'=>'single', 'path'=>storage_path('logs/laravel.log'), 'level'=>'debug', ], 'daily'=>[ 'driver'=>'daily', 'path'=>storage_path('logs/laravel.log'), 'level'=>'debug', 'days'=>14, ], (中略) 'user-register'=>[ 'driver'=>'daily', 'level'=>'debug', 'path'=>storage_path('logs/user-register.log'), 'days'=>90, ], ], |
stack, single, dailyはデフォルトの設定項目で、user-register
が追記した項目です。
- driver: 前述のコードで
new Logger()
した時の引数に相当します。Monologでは複数のchannelを登録し、一度に複数の出力先にログを吐き出すことが可能です(このへんがまだ理解が浅く、正しい解釈なのか不安です…)。一番上のstack
だけは少し特殊で、複数のchannelを記述して一括登録することが可能です(channelsが配列になっているのはそのためのようです)。 - level: 前述の
$log_level
に相当します。 - path: 前述の
$log_path
に相当します。 - days: 前述の
$days
に相当します。
アプリケーションでは以下のように記述することで、最初のコードと同様にstorage/logs/user-register-[YYYY-MM-DD].log
にログが出力されます。コード量が目に見えて減りました!複雑な仕様でなければ、設定ファイルのへ記述で済ませてしまうのがベターだと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | useIlluminate\Support\Facades\Log; protectedfunctioncreate(array$data) { $user=User::create([ 'name'=>$data['name'], 'email'=>$data['email'], 'password'=>Hash::make($data['password']), ]); Log::setDefaultDriver('user-register'); Log::info(sprintf('ユーザーID:%sが登録されました。',$user->id)); return$user; } |
おまけ:ログレベルについて
上述のPSR-3で定義されているログレベルはあくまでも目安です。今回の例では「正常にユーザー登録が完了した」ときのログですのでやerrorやwarningではおかしいですが、noticeなのか、infoなのかは要件次第になるでしょう。
以下のページでログレベル一覧および一例が完結にまとまっていましたので、紹介いたします。
さいごに
「ログの出し分けをしたい」という要件から始まって、Laravelのログ出力について調査したのですが、一度理解してしまえば実に簡単です。豊富な出力先を選べるのもいいですね。