デフォルトではコマンドでエラーが発生しても何も出力されない。
必要に応じてtry-catchを書くのは面倒だし、細かくtry-catchする必要もない。
面倒なので継承するだけでいろいろやってくれるラッパークラスを作った。
command実行時にいろいろするラッパークラス
コマンド開始・終了時にログ出力(処理時間、メモリ使用量)
コマンド中に発生したException
を拾ってメッセージから必要な個所だけ抜き取って出力
app/Libs/Command/LogCommand.php
namespace App\Libs\Command;
use Illuminate\Console\Command;
use \Symfony\Component\Console\Input\InputInterface;
use \Symfony\Component\Console\Output\OutputInterface;
use \Exception;
use \InvalidArgumentException;
use \BadMethodCallException;
class LogCommand extends Command
{
public function __construct()
{
parent::__construct();
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$return = -1;
$memory_limit = '4096M'; // configとか別の場所で設定できるように
ini_set('memory_limit', $memory_limit);
$params = $input->getArguments();
unset($params['command']);
$time = microtime(true);
app()->BatchLog->notice($this->getName() . ' start. ' . json_encode($params) . ' [memory_limit=' . $memory_limit . ']');
try {
$return = $this->laravel->call([$this, 'handle']);
} catch (InvalidArgumentException $e) {
self::_error_trace($e);
} catch (BadMethodCallException $e) {
self::_error_trace($e);
} catch (Exception $e) {
self::_error_trace($e);
}
$end_time = microtime(true);
$diff_time = round($end_time - $time, 3);
$max = str_replace('M', '', $memory_limit);
$peak = round(memory_get_peak_usage(true) / 1024 / 1024, 3);
$used = ($max != 0) ? round((int)$peak / (int)$max * 100, 3) : '--';
app()->BatchLog->notice($this->getName() . ' end. exec_time(s)=' . $diff_time . '; ' . sprintf('Memory usage: %s %% used. (max: %sM, now: %sM)', $used, $max, $peak) . '');
return $return;
}
/**
* @param Exception|InvalidArgumentException|BadMethodCallException $e
*/
private function _error_trace($e)
{
$ts = explode(PHP_EOL, $e->getTraceAsString());
$trace = $e->getMessage() . PHP_EOL;
foreach ($ts as $v) {
if (strpos($v, '/app/Console/Commands/') !== false) {
$trace .= $v . PHP_EOL;
}
}
self::error($trace);
}
public function debug($string, $verbosity = null)
{
parent::line($string, null, $verbosity);
app()->BatchLog->debug($string);
}
public function info($string, $verbosity = null)
{
parent::line($string, null, $verbosity);
app()->BatchLog->info($string);
}
public function notice($string, $verbosity = null)
{
parent::line($string, null, $verbosity);
app()->BatchLog->notice($string);
}
public function warning($string, $verbosity = null)
{
$this->warn($string, $verbosity);
}
public function warn($string, $verbosity = null)
{
parent::line($string, null, $verbosity);
app()->BatchLog->warning($string);
}
public function error($string, $verbosity = null)
{
parent::line($string, null, $verbosity);
app()->BatchLog->error($string);
}
}
php artisan make:command xxxx
で作ったクラスの継承元をCommand
からLogCommand
に置き換えます。
LogCommandを使うために必要なクラスなど
バッチ処理用のログ出力クラス
storage/logs/batch/
にログ出力する。
app/Log/BatchLog.php
namespace App\Log;
use Illuminate\Log\LogServiceProvider;
use Illuminate\Log\Writer;
class BatchLog extends LogServiceProvider
{
public function register()
{
$this->app->singleton('BatchLog', function () {
return $this->createLogger();
});
}
protected function channel()
{
return 'batchlog';
}
protected function configureSingleHandler(Writer $log)
{
$log->useFiles(
$this->path() . $this->getFileName(),
$this->logLevel()
);
}
protected function configureDailyHandler(Writer $log)
{
$log->useDailyFiles(
$this->path() . $this->getFileName(), $this->maxFiles(),
$this->logLevel()
);
}
protected function configureSyslogHandler(Writer $log)
{
$log->useSyslog('batchlog', $this->logLevel());
}
private function path(): string
{
return env('LOG_DIR', $this->app->storagePath() . '/logs/batch/');
}
private function getFileName(): string
{
return 'batch.log';
}
}
ログ出力クラスのサービスプロバイダ
php artisan make:provider BatchLogServiceProvider
app/Providers/BatchLogServiceProvider.phpを編集
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class BatchLogServiceProvider extends ServiceProvider
{
protected $defer = true;
public function register()
{
app()->register(\App\Log\BatchLog::class);
}
public function provides()
{
return ['BatchLog'];
}
}
このクラスをconfig/app.php
に追記しておく。