Laravel Monolog Cascadeを使用してログレベル毎に出力するファイルを変更する
概要
ログレベル毎に出力するファイルを変更したい
Laravel標準ではdailyでログファイルをローテートは出来る程度
.env
APP_LOG=daily
storage/logs
laravel-2016-10-04.log laravel-2016-10-05.log laravel-2016-10-06.log
Monolog Cascadeを使用して、ログレベル毎に出力するファイルを変更する github.com
手順
インストール
composer.jsonに以下を追記後、composer updateを実行
"require": { "theorchard/monolog-cascade": "^0.4.0" }
設定
https://github.com/theorchard/monolog-cascade Configuration structureを参考に作成
config/monolog.php
<?php return [ 'version' => 1, 'formatters' => [ 'dashed' => [ 'format' => "%datetime%-%channel%.%level_name% - %message% %context% %extra%\n", 'include_stacktraces' => true ], ], 'handlers' => [ //------------------------------------------------- // Admin // ------------------------------------------------ 'admin_info' => [ 'class' => 'Monolog\Handler\RotatingFileHandler', 'level' => 'INFO', 'filename' => env('LOG_ADMIN_INFO_PATH', storage_path('logs/admin_info.log')), 'maxFiles' => 5, 'formatter' => 'dashed', 'processors' => ['web_processor', 'introspection_processor', 'login_user_processor'], ], 'admin_error' => [ 'class' => 'Monolog\Handler\RotatingFileHandler', 'level' => 'ERROR', 'filename' => env('LOG_ADMIN_ERROR_PATH', storage_path('logs/admin_error.log')), 'maxFiles' => 5, 'formatter' => 'dashed', 'processors' => ['web_processor', 'introspection_processor', 'login_user_processor'], ], // WARNINGのみ出力 '_admin_warning' => [ 'class' => 'Monolog\Handler\RotatingFileHandler', 'level' => 'WARNING', 'filename' => env('LOG_ADMIN_WARNING_PATH', storage_path('logs/admin_warning.log')), 'maxFiles' => 5, 'formatter' => 'dashed', 'processors' => ['web_processor', 'introspection_processor', 'login_user_processor'], ], 'admin_warning' => [ 'class' => 'Monolog\Handler\FilterHandler', 'handler' => '_admin_warning', 'minLevelOrList' => ['WARNING'], ], //------------------------------------------------- // Front // ------------------------------------------------ 'front_info' => [ 'class' => 'Monolog\Handler\RotatingFileHandler', 'level' => 'INFO', 'filename' => env('LOG_FRONT_INFO_PATH', storage_path('logs/front_info.log')), 'maxFiles' => 5, 'formatter' => 'dashed', 'processors' => ['web_processor', 'introspection_processor'], ], 'front_error' => [ 'class' => 'Monolog\Handler\RotatingFileHandler', 'level' => 'ERROR', 'filename' => env('LOG_FRONT_ERROR_PATH', storage_path('logs/front_error.log')), 'maxFiles' => 5, 'formatter' => 'dashed', 'processors' => ['web_processor', 'introspection_processor'], ], // WARNINGのみ出力 '_front_warning' => [ 'class' => 'Monolog\Handler\RotatingFileHandler', 'level' => 'WARNING', 'filename' => env('LOG_FRONT_WARNING_PATH', storage_path('logs/front_warning.log')), 'maxFiles' => 5, 'formatter' => 'dashed', 'processors' => ['web_processor', 'introspection_processor'], ], 'front_warning' => [ 'class' => 'Monolog\Handler\FilterHandler', 'handler' => '_front_warning', 'minLevelOrList' => ['WARNING'], ], ], 'processors' => [ // IP,URL,HTTP METHOD,referrer 'web_processor' => [ 'class' => 'Monolog\Processor\WebProcessor' ], // 出力ファイル名、出力行 'introspection_processor' => [ 'class' => 'Monolog\Processor\IntrospectionProcessor', 'skipClassesPartials' => [ 'Monolog\\', 'Illuminate\\', ], ], // ログイン情報 'login_user_processor' => [ 'class' => 'App\Services\Monolog\Processor\LoginUserProcessor' ], ], 'loggers' => [ // このキーをMonologSetting::change()で指定 'admin' => [ 'handlers' => ['admin_info', 'admin_error', 'admin_warning'] ], 'front' => [ 'handlers' => ['front_info', 'front_error', 'front_warning'] ] ] ];
Monolog Cascadeに差し替え
LaravelのMonolog Loggerと差し替える
app/Services/Monolog/MonologSetting.php
<?php namespace App\Services\Monolog; use Cascade\Cascade; use Illuminate\Log\Writer; use Log; class MonologSetting { /** * ログ設定を変更する * @param string $logName 変更名 config/monolog.phpのhandlersキー */ public static function change($logName) { // 登録済みインスタンスを削除 Log::clearResolvedInstances(); app()->instance('log', new Writer(Cascade::getLogger($logName))); } }
Laravelの登録方法を参考にした
<?php namespace Illuminate\Foundation\Bootstrap; use Illuminate\Log\Writer; use Monolog\Logger as Monolog; use Illuminate\Contracts\Foundation\Application; class ConfigureLogging { /** * Register the logger instance in the container. * * @param \Illuminate\Contracts\Foundation\Application $app * @return \Illuminate\Log\Writer */ protected function registerLogger(Application $app) { $app->instance('log', $log = new Writer( new Monolog($app->environment()), $app['events']) ); return $log; } }
Facadeを追加
<?php namespace App\Facades; use Illuminate\Support\Facades\Facade; class MonologSetting extends Facade { protected static function getFacadeAccessor() { return 'monolog_setting'; } }
config\app.php
<?php return [ 'aliases' => [ 'MonologSetting' => App\Facades\MonologSetting::class, // ここを追加 ], ];
サービスプロバイダー
MonologSettingのバインドとFront/Admin/コンソールでロガーを切替
artisanコマンドで雛型作成
php artisan make:provider MonologSettingServiceProvider Provider created successfully.
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use MonologSetting; use Cascade\Cascade; class MonologSettingServiceProvider extends ServiceProvider { /** * Bootstrap the application services. * * @return void */ public function boot() { Cascade::fileConfig(config_path('monolog.php')); $changeName = null; // コマンド実行時とwebアクセス時で設定を変更 if (php_sapi_name() == 'cli') { $changeName = 'console'; } elseif (str_is('/admin/*', env('REQUEST_URI'))) { $changeName = 'admin'; } if (!is_null($changeName)) { MonologSetting::change($changeName); } } /** * Register the application services. * * @return void */ public function register() { // キーはMonologSettingファサードのgetFacadeAccessor()の戻り値と一致 \App::bind('monolog_setting', function() { return new \App\MonologSetting; }); } }
config\app.php
'providers' => [
/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
App\Providers\MonologSettingServiceProvider::class, // add
],
ログインユーザ名を出力
認証認可はSentinel Manual :: Cartalystを使用
<?php namespace App\Services\Monolog\Processor; use Sentinel; class LoginUserProcessor { /** * @param array $record * @return array */ public function __invoke(array $record) { if (Sentinel::check()) { $user = Sentinel::getUser(); $record['extra']['username'] = $user->getUserLogin(); } return $record; } }
結果
変更前
storage/logs/laravel-2016-10-13.log
[2016-10-13 07:02:52] local.WARNING: array ( '_method' => 'PUT', '_token' => 'E5ola1t7HaX79kfkEcZW3oNxhdYau10SdxDUuBDc', 'first_name' => '', 'last_name' => '', 'email' => 'admin@xxxxx.xxx', 'password' => 'xxxxx', 'password_confirm' => '', ) [2016-10-13 07:02:52] local.WARNING: array ( 'first_name' => array ( 0 => 'The first name field is required.', ), 'last_name' => array ( 0 => 'The last name field is required.', ), 'email' => array ( 0 => 'The email has already been taken.', ), ) [2016-10-13 07:05:51] local.ERROR: exception 'Symfony\Component\HttpKernel\Exception\NotFoundHttpException' in \vendor\laravel\framework\src\Illuminate\Routing\RouteCollection.php:161 Stack trace: #0 \vendor\laravel\framework\src\Illuminate\Routing\Router.php(821): Illuminate\Routing\RouteCollection->match(Object(Illuminate\Http\Request))
変更後
errorレベル
storage/logs/front_error-2016-10-13.log
2016-10-13 07:31:04-front.ERROR - exception 'Symfony\Component\HttpKernel\Exception\NotFoundHttpException' in vendor\laravel\framework\src\Illuminate\Routing\RouteCollection.php:161 Stack trace: #0 vendor\laravel\framework\src\Illuminate\Routing\Router.php(821): Illuminate\Routing\RouteCollection->match(Object(Illuminate\Http\Request))
warnレベル
storage/logs/front_warning-2016-10-13.log
2016-10-13 07:31:45-front.WARNING - array ( '_method' => 'PUT', '_token' => 'E5ola1t7HaX79kfkEcZW3oNxhdYau10SdxDUuBDc', 'first_name' => '', 'last_name' => '', 'email' => 'admin@xxxxx.xxx', 'password' => 'xxxxx', 'password_confirm' => '', ) 2016-10-13 07:31:45-front.WARNING - array ( 'first_name' => array ( 0 => 'The first name field is required.', ), 'last_name' => array ( 0 => 'The last name field is required.', ), 'email' => array ( 0 => 'The email has already been taken.', ), )