概要
ログ周りの設定レシピ、3品。今回はその3品目。
- Laravel5.4 ログ周りの設定 1/3 開始・終了ログを残す
- Laravel5.4 ログ周りの設定 2/3 クエリログを別ファイルで
- Laravel5.4 ログ周りの設定 3/3 ミリ秒に出力場所を添えて(本記事)
やりたいこと
- ログ出力日時をミリ秒まで表示
- ログ出力場所を表示(メソッド名・行数)
- プロセスIDもついでに表示。
storage\log\app.log
[2017-06-19 12:24:42.988618] local.INFO: -- Startup {"method":"GET","uri":"/"} {"pid":2310,"line":"App\\Bootstrap\\ApplicationLog->startupLog:68"}
[2017-06-19 12:24:43.064103] local.DEBUG: Hello Log Sample {"pid":2310,"line":"App\\Http\\Controllers\\HomeController->index:12"}
[2017-06-19 12:24:43.073957] local.INFO: -- Shutdown {"time":"108.714[ms]","memory":"2048[kb]"} {"pid":2310,"line":"App\\Bootstrap\\ApplicationLog->handleShutdownLog:84"}
環境
Laravel 5.4.25
PHP 7.1.3
実装手順
- Illuminate\Log\Writerクラスを継承したクラスを作成し、getDefaultFormatterメソッドを上書き
- Monolog用プロセッサ作成(必要なら。標準で同機能のものがあります。)
- Writerクラス差し替え & Monolog用プロセッサを登録
以下、サンプル
前回の続きで、LogServiceProviderを差し替えた前提です。
一応動作確認はしていますが、サンプルをそのまま使う場合は自己責任で。
Writerクラス作成
app\Utils\Monolog\Writer.php
<?php
namespace App\Utils\Monolog;
use Illuminate\Log\Writer as BaseWriter;
use Monolog\Formatter\LineFormatter;
/**
* Monolog用Writer
* 日時をマイクロ秒まで表示
*
* @package app.Utils.Monolog
*/
class Writer extends BaseWriter
{
/**
* Get a default Monolog formatter instance.
*
* @return \Monolog\Formatter\LineFormatter
*/
protected function getDefaultFormatter()
{
return new LineFormatter(null, 'Y-m-d H:i:s.u', true, true);
}
}
Monolog用プロセッサ作成(出力場所)
Monologで用意されているものを少し改良。
file, line, class, functionの4つに分けて表示されるのは見づらかったため、簡易表示版。
app\Utils\Monolog\Processor\IntrospectionProcessor.php
<?php
namespace App\Utils\Monolog\Processor;
use Monolog\Logger;
/**
* Monolog用プロセッサ
* 標準IntrospectionProcessorの簡略版。
* ログ出力している場所を出力します。
*
* @package app.Utils.Monolog.Processor
*/
class IntrospectionProcessor
{
private $level;
private $skipClassesPartials;
public function __construct($level = Logger::DEBUG, array $skipClassesPartials = ['Monolog\\', 'Illuminate\\'])
{
$this->level = Logger::toMonologLevel($level);
$this->skipClassesPartials = $skipClassesPartials;
}
/**
* @param array $record
* @return array
*/
public function __invoke(array $record)
{
// return if the level is not high enough
if ($record['level'] < $this->level) {
return $record;
}
$trace = debug_backtrace();
// skip first since it's always the current method
array_shift($trace);
// the call_user_func call is also skipped
array_shift($trace);
$i = 0;
while (isset($trace[$i]['class'])) {
foreach ($this->skipClassesPartials as $part) {
if (strpos($trace[$i]['class'], $part) !== false) {
$i++;
continue 2;
}
}
break;
}
$line = null;
if (isset($trace[$i]['class'])) {
$line = $trace[$i]['class'];
if (isset($trace[$i]['class'])) {
$line = $line . '->' . $trace[$i]['function'];
}
} else if (isset($trace[$i - 1]['file'])) {
$line = $trace[$i - 1]['file'];
}
if (null !== $line && isset($trace[$i - 1]['line'])) {
$line = $line . ':' . $trace[$i - 1]['line'];
}
$record['extra']['line'] = $line;
return $record;
}
}
Monolog用プロセッサ作成(プロセスID)
Monologで用意されているものと同じです。
キーの名前を省略したかっただけです。(process_id > pid)
app\Utils\Monolog\Processor\IntrospectionProcessor.php
<?php
namespace App\Utils\Monolog\Processor;
/**
* Monolog用プロセッサ
* 標準ProcessIdProcessorの出力キーの文字数が長いため、簡略版
*
* @package app.Utils.Monolog.Processor
*/
class ProcessIdProcessor
{
/**
* @param array $record
* @return array
*/
public function __invoke(array $record)
{
$record['extra']['pid'] = getmypid();
return $record;
}
}
Writer差し替え & Monolog用プロセッサ登録
app\Providers\LogServiceProvider.php
<?php
namespace App\Providers;
// 差し替え
//use Illuminate\Log\Writer;
use App\Utils\Monolog\Writer;
// 追加
use App\Utils\Monolog\Processor\IntrospectionProcessor;
use App\Utils\Monolog\Processor\ProcessIdProcessor;
use Carbon\Carbon;
use Illuminate\Support\ServiceProvider;
use Monolog\Logger as Monolog;
/**
* ロガー登録プロバイダ
*
* @package app.Providers
*/
class LogServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->singleton('log', function () {
return $this->createAppLogger();
});
$this->app->singleton('sql-log', function () {
return $this->createSqlLogger();
});
}
/**
* Create the app logger.
*
* @return \Illuminate\Log\Writer
*/
public function createAppLogger()
{
// プロセッサーを登録
$processors = [
new ProcessIdProcessor(),
new IntrospectionProcessor()
];
$log = new Writer(
new Monolog($this->channel(), [], $processors), $this->app['events']
);
$this->configureHandler($log, 'app');
return $log;
}
/**
* Create the sql logger.
*
* @return \Illuminate\Log\Writer
*/
public function createSqlLogger()
{
// プロセッサーを登録
$processors = [
new ProcessIdProcessor(),
];
$log = new Writer(
new Monolog($this->channel(), [], $processors), $this->app['events']
);
$this->configureHandler($log, 'sql');
return $log;
}
//以下、省略
さいごに
3回に分けて、よくやってるログ設定をまとめてみました。
ログ大事です。何かあった時に調査しやすいようログを適切に書きましょう。(自分に言い聞かせてる)
以上です。