LoginSignup
5
3

More than 5 years have passed since last update.

Laravel5.4 ログ周りの設定 3/3 ミリ秒に出力場所を添えて

Last updated at Posted at 2017-06-19

概要

ログ周りの設定レシピ、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

実装手順

  1. Illuminate\Log\Writerクラスを継承したクラスを作成し、getDefaultFormatterメソッドを上書き
  2. Monolog用プロセッサ作成(必要なら。標準で同機能のものがあります。)
  3. 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回に分けて、よくやってるログ設定をまとめてみました。
ログ大事です。何かあった時に調査しやすいようログを適切に書きましょう。(自分に言い聞かせてる)

以上です。

5
3
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
5
3