LoginSignup
16
12

More than 5 years have passed since last update.

Laravel Commandでお手軽ログ出力

Posted at

デフォルトではコマンドでエラーが発生しても何も出力されない。
必要に応じて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に追記しておく。

16
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
12