概要
Laravelのアプリケーションログの出力先を.envで変更できるようにして、さらにフォーマットも変更したかったので調べた内容をメモしておく。
ログのフォーマットについて
いろいろとありそうですが、LTSV形式が使いやすそうだったので使ってみる。
自分でMonologのFormatterを作るのも面倒なのでGoogle先生に聞いたところ良さそうのが見つかる。
■ hikaeme/monolog-ltsv-formatter
https://packagist.org/packages/hikaeme/monolog-ltsv-formatter
上記ライブラリを利用することにします。
# インストール
$ composer require hikaeme/monolog-ltsv-formatter
カスタマイズ方法について検討
Laravelのログ出力のカスタマイズを調べてみるとマニュアルには、
configureMonologUsingメソッドでと紹介されているが書いてみると・・・イマイチ微妙。
$app->configureMonologUsing(function($monolog) {
$level = \Monolog\Logger::DEBUG;
$format = "%datetime%,%level_name%,%message%,%context%,%extra%\n";
$monolog->pushProcessor(new \Monolog\Processor\IntrospectionProcessor(
$level, ['Monolog\\', 'Illuminate\\',]
));
$monolog->pushHandler(
$handler = new \Monolog\Handler\StreamHandler(
storage_path('logs/laravel.log'),
$level
)
);
$handler->setFormatter(new Monolog\Formatter\LineFormatter($format));
});
<微妙と思う点について>
- config/app.phpにログの設定があるが、上記方法でカスタマイズすると設定が反映されない
- ログレベルなどの設定も.envやconfigの設定が反映されない(できなくもないが・・・)
他の方法を探すと「LogServiceProvider」の差し替えで行けそう。
■Laravel・Lumenでログ出力先を変更する
https://k2ss.info/archives/1629
こちらの方法を採用してみる。
LogServiceProviderの実装
Illuminate\Log\Writerの「 parseLevel 」メソッドが、protectedで利用できず、仕方がなく移植。
<?php
namespace App\Providers;
use InvalidArgumentException;
use Illuminate\Log\LogServiceProvider AS BaseLogServiceProvider;
use Illuminate\Log\Writer;
use Monolog\Logger AS MonologLogger;
use Monolog\Processor\IntrospectionProcessor;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\RotatingFileHandler;
use Hikaeme\Monolog\Formatter\LtsvFormatter;
class LogServiceProvider extends BaseLogServiceProvider
{
/**
* The Log levels.
* ※「Illuminate\Log\Writer」から移植
*
* @var array
*/
protected $levels = [
'debug' => MonologLogger::DEBUG,
'info' => MonologLogger::INFO,
'notice' => MonologLogger::NOTICE,
'warning' => MonologLogger::WARNING,
'error' => MonologLogger::ERROR,
'critical' => MonologLogger::CRITICAL,
'alert' => MonologLogger::ALERT,
'emergency' => MonologLogger::EMERGENCY,
];
/**
* singleモードの出力
*
* @param \Illuminate\Log\Writer $log
* @return void
* @throws \Exception
*/
protected function configureSingleHandler(Writer $log)
{
// コメントアウト (フォーマットが変更できない)
#$log->useFiles(
# $this->app->storagePath().'/logs/laravel.log',
# $this->logLevel()
#);
$monolog = $log->getMonolog();
// フォーマット変更 (LTSV形式)
$monolog->pushHandler(
$handler = new StreamHandler(
$this->path().$this->file(),
$this->parseLevel($this->logLevel())
)
);
$handler->setFormatter(new LtsvFormatter());
// ログ追加 (ファイル名、行番号、クラス名、メソッド名)
$monolog->pushProcessor(
new IntrospectionProcessor(MonologLogger::DEBUG, ['Monolog\\', 'Illuminate\\',])
);
}
/**
* 日付ローテートモードでの出力
*
* @param \Illuminate\Log\Writer $log
* @return void
* @throws \Exception
*/
protected function configureDailyHandler(Writer $log)
{
// コメントアウト (フォーマットが変更できない)
#$log->useDailyFiles(
# $this->app->storagePath().'/logs/laravel.log', $this->maxFiles(),
# $this->logLevel()
#);
$monolog = $log->getMonolog();
// フォーマット変更 (LTSV形式)
$monolog->pushHandler(
$handler = new RotatingFileHandler(
$this->path().$this->file(),
$this->maxFiles(),
$this->parseLevel($this->logLevel())
)
);
$handler->setFormatter(new LtsvFormatter());
// ログ追加 (ファイル名、行番号、クラス名、メソッド名)
$monolog->pushProcessor(
new IntrospectionProcessor(MonologLogger::DEBUG, ['Monolog\\', 'Illuminate\\',])
);
}
/**
* ログ出力先
*
* @return string
*/
private function path(): string
{
return env('APP_LOG_DIR', $this->app->storagePath().'/logs/');
}
/**
* ファイル名
*
* @return string
*/
private function file(): string
{
return 'laravel.log';
}
/**
* Parse the string level into a Monolog constant.
* ※「Illuminate\Log\Writer」から移植
*
* @param string $level
* @return int
*
* @throws \InvalidArgumentException
*/
protected function parseLevel($level): int
{
if (isset($this->levels[$level])) {
return $this->levels[$level];
}
throw new InvalidArgumentException('Invalid log level.');
}
}
独自のApplicationクラス
LogServiceProviderを差し替えるために、独自クラスを作成する。
<?php
namespace App;
use App\Providers\LogServiceProvider;
use Illuminate\Events\EventServiceProvider;
use Illuminate\Routing\RoutingServiceProvider;
/**
* アプリケーションクラス
* ※ ログサービスプロバイダを変更したいため、overwrite
*
* @package app.Providers
*/
class Application extends \Illuminate\Foundation\Application
{
/**
* Register all of the base service providers.
*
* @return void
*/
protected function registerBaseServiceProviders()
{
$this->register(new EventServiceProvider($this));
$this->register(new LogServiceProvider($this));
$this->register(new RoutingServiceProvider($this));
}
}
bootstrap/app.php
上記で作成した独自Applicationクラスに差し替えるため、修正。
<?php
/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------
|
| The first thing we will do is create a new Laravel application instance
| which serves as the "glue" for all the components of Laravel, and is
| the IoC container for the system binding all of the various parts.
|
*/
// Applicationクラスを差し替え
// $app = new Illuminate\Foundation\Application(
$app = new \App\Application(
realpath(__DIR__.'/../')
);
試してみる
クエリの実行ログを出力してみる。
<?php
namespace App\Providers;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
// アプリケーションで実行される各SQLクエリのログ出力
DB::listen(function ($query) {
// 改行と連続スペースを取り除く
$sql = trim(preg_replace('/\s+/', ' ', str_replace(["\r\n", "\r", "\n"], '', $query->sql)));
\Log::debug($sql);
\Log::debug($query->bindings);
\Log::debug($query->time);
});
}
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
}
実行してみると、下記のようにLTSV形式のログが出力される。
time:2018-07-12 12:13:48 level:DEBUG message:SELECT id, name FROM users WHERE id = ? ; file:/var/www/www.example.com/app/Providers/AppServiceProvider.php line:21 class:App\Providers\AppServiceProvider function:App\Providers\{closure}
time:2018-07-12 12:13:48 level:DEBUG message:array (\n 0 => '1',\n) file:/var/www/www.example.com/app/Providers/AppServiceProvider.php line:22 class:App\Providers\AppServiceProvider function:App\Providers\{closure}
time:2018-07-12 12:13:48 level:DEBUG message:16.79 file:/var/www/www.example.com/app/Providers/AppServiceProvider.php line:23 class:App\Providers\AppServiceProvider function:App\Providers\{closure}
ログの出力場所を変えてみる。
パーミッションの関係で他のところに出力し難かったので、とりあえず、storageフォルダ直下に出力してみる。
.envファイルで出力先のパスを指定する。
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:*********************************=
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_LOG_DIR=/var/www/www.example.com/storage/ <- ここに追加
APP_URL=http://localhost
実行してみると、下記のようにLTSV形式のログが出力される。
time:2018-07-12 12:13:48 level:DEBUG message:SELECT id, name FROM users WHERE id = ? ; file:/var/www/www.example.com/app/Providers/AppServiceProvider.php line:21 class:App\Providers\AppServiceProvider function:App\Providers\{closure}
time:2018-07-12 12:13:48 level:DEBUG message:array (\n 0 => '1',\n) file:/var/www/www.example.com/app/Providers/AppServiceProvider.php line:22 class:App\Providers\AppServiceProvider function:App\Providers\{closure}
time:2018-07-12 12:13:48 level:DEBUG message:16.79 file:/var/www/www.example.com/app/Providers/AppServiceProvider.php line:23 class:App\Providers\AppServiceProvider function:App\Providers\{closure}
以上