LoginSignup
31
38

More than 3 years have passed since last update.

Laravelでログ出力を行う

Last updated at Posted at 2020-05-15

目次

Laravelの記事一覧は下記
PHPフレームワークLaravelの使い方

Laravelバージョン

動作確認はLaravel Framework 7.19.1で行っています

前提条件

eclipseでLaravel開発環境を構築する。デバッグでブレークポイントをつけて止める。(WindowsもVagrantもdockerも)
本記事は上記が完了している前提で書かれています
プロジェクトの作成もapacheの設定も上記で行っています

Controllerにメソッド追加

(1) /sample/app/Http/Controllers/SampleController.phpに下記を追記
use Illuminate\Support\Facades\Log;

(2) /sample/app/Http/Controllers/SampleController.phpにlogメソッドを追記

    public function log(Request $request)
    {
        Log::emergency('ログサンプル', ['memo' => 'sample1']);
        Log::alert('ログサンプル', ['memo' => 'sample1']);
        Log::critical('ログサンプル', ['memo' => 'sample1']);
        Log::error('ログサンプル', ['memo' => 'sample1']);
        Log::warning('ログサンプル', ['memo' => 'sample1']);
        Log::notice('ログサンプル', ['memo' => 'sample1']);
        Log::info('ログサンプル', ['memo' => 'sample1']);
        Log::debug('ログサンプル', ['memo' => 'sample1']);

        return view('sample.log');
    }

Logクラスのログ出力メソッド名はログレベルに相当します
emergencyは最も重要度が高く、debugは最も重要度が低いです

(2) /sample/routes/web.phpに下記を追記
Route::get('sample/log', 'SampleController@log');

viewの作成

/sample/resources/views/sample/log.blade.phpファイル作成

log.blade.php
<html>
    <head>
        <title>sample</title>
    </head>
    <body>
        <div>log</div>
    </body>
</html>

logの設定

(1) /sample/config/logging.phpファイル修正
logging.phpは配列を返すファイルになっています
default要素の値が使用するログチャンネルとなります
ログ出力の際には、どこ(ファイル、DB、メール等)に何(ファイル名、行番号、リクエストURL等)を、どのように(日時の形式等)出力するかを決めなければなりません
どこ、何、どのようにの組み合わせを定義したものをログチャンネルと呼ぶと考えて差し支えないと思います
default要素はenv('LOG_CHANNEL', 'stack')となっていると思います。つまりstackチャンネルを使用します

stackチャンネルはどのような定義になっているか見ていきます

logging.phpファイルのchannels要素に様々なログチャンネルが定義されています
'channels'=>'stack'要素がstackチャンネルです
'channels'=>'stack'要素(stackチャンネル)を修正します

    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'ignore_exceptions' => false,
            'channels' => ['single', 'daily'],
            'name' => 'stack-channel',
        ],
     ‥‥

channels要素を修正し、name要素を追加しました
stackチャンネルというのは複数のログチャンネルを1つにまとめたものです。したがって、使用するログチャンネルを'channels'=>'stack'=>'channels'要素に書くだけです
今回はsingleチャンネルとdailyチャンネルを使用する設定にしました
name要素はチャンネル名です。お好きな名前を設定してください

では、'channels'=>'single'要素(singleチャンネル)を修正します

    'channels' => [
     ‥‥
        'single' => [
            'driver' => 'single',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
            'tap' => [App\Logging\SampleTap::class],
        ],
     ‥‥

singleチャンネルは1つのファイルにログを出力するチャンネルです。
level要素はどのログレベル以上をログファイルに出力するかを設定しています。例えば、infoと設定した場合、infoより重要度の低いdebugはメソッドが呼ばれたとしてもログに出力されません
path要素でstorage/logs/laravel.logにログを出力する設定になっています。これでどこにログを出力するかは決まりました
次に、何を、どのように出力するかを決めます。それがtap要素です。tap要素にはSampleTapクラスを設定しました
これからSampleTapクラスを作成します

(2) Tapクラスの修正
/sample/app/Loggingフォルダ作成
/sample/app/Logging/SampleTap.phpファイル作成

SampleTap.php
<?php

namespace App\Logging;

use Monolog\Logger;
use Monolog\Formatter\LineFormatter;
use Monolog\Processor\HostnameProcessor;
use Monolog\Processor\WebProcessor;
use Monolog\Processor\IntrospectionProcessor;
use App\Logging\SampleProcessor;

class SampleTap
{
    const FORMAT = "[%datetime%] %level_name% %channel% %message% %extra.file% %extra.line% %extra.class% %extra.function% %extra.hostname% %extra.url% %extra.ip% %extra.http_method% %extra.server% %extra.referrer% %extra.custom% %context.memo%\n";

    public function __invoke($logger)
    {
        $hostnameProcessor = new HostnameProcessor();
        $webProcessor = new WebProcessor();
        $introspectionProcessor = new IntrospectionProcessor(Logger::DEBUG, ['Illuminate\\']);
        $sampleProcessor = new SampleProcessor();

        $lineFormatter = new LineFormatter(static::FORMAT);

        foreach ($logger->getHandlers() as $handler) {
            $handler->pushProcessor($webProcessor);
            $handler->pushProcessor($hostnameProcessor);
            $handler->pushProcessor($introspectionProcessor);
            $handler->pushProcessor($sampleProcessor);
            $handler->setFormatter($lineFormatter);
        }
    }
}

pushProcessorに渡しているのが何を出力するか
setFormatterに渡しているのがどのようにを出力するか
を定義しているクラスです

まずはProcessorを見ていきましょう
Laravelのログ出力はMonologを使用しています
したがってMonologのクラスを使用していきます
HostnameProcessor、WebProcessor、IntrospectionProcessorはMonologが提供してくれているクラスです
他にもProcessorクラスを提供してくれています。
Monologが提供しているProcessor
HostnameProcessorはホスト名を出力してくれます
WebProcessorはリクエストURI、リクエストメソッド、クライアントIP、サーバ名、リファラを出力してくれます
IntrospectionProcessorはファイル、行番号、クラス、関数名を出力してくれます
Monologが提供しているProcessorでは出力されない値をログに出力したい場合、自分でProcessorクラスを作成することになります
SampleProcessorクラスは今回自作したProcessorです。後述します

つぎにFormatterを見ていきましょう
LineFormatterはMonologが提供してくれているクラスです
他にもFormatterクラスを提供してくれています。
Monologが提供しているFormatter
LineFormatterはコンストラクタの第一引数に与えられた文字列に従ってフォーマットしてくれます
今回はSampleTapクラスのFORMAT定数を与えています
LineFormatterは%で囲われた文字列を下記の通りに置換します
%datetime%:ログ出力の日時
%level_name%:ログレベル。Log::error関数でログ出力した場合はerrorがログレベルです
%channel%:logging.phpファイルの'channels'=>'stack'=>'name'
%message%:ログ出力関数の第一引数。Log::error('ログサンプル', ['memo' => 'sample1']);とログ出力した場合、'ログサンプル'
%context.xxx%:ログ出力関数の第二引数。Log::error('ログサンプル', ['memo' => 'sample1']);とログ出力した場合、%context.memo%が'sample1'に置換される
%extra.xxx%:Processorクラスで出力する値。あとでSampleProcessorを作るときに説明します

Formatterを自作することもできますが、ほとんどの場合、Monologが提供しているFormatterで十分でしょう
もし、Formatterを自作する場合は、Monolog\Formatter\FormatterInterfaceをimplementsしたクラスを作ってください

(3) Processorクラスの修正
自作のProcessorクラスをつくります
/sample/app/Logging/SampleProcessor.phpファイル作成

SampleProcessor.php

namespace App\Logging;

use Monolog\Processor\ProcessorInterface;

class SampleProcessor implements ProcessorInterface
{
    public function __invoke(array $record)
    {
        $record['extra']['custom'] = 'sample_extra';
        return $record;
    }
}

$record['extra']['custom']に値を入れて返すと
フォーマット文字列内の%extra.custom%部分が$record['extra']['custom']の値に置換されます
第一要素を'extra'とするのはProcessorを使う上での決まりです
先ほど使用したMonologが提供しているProcessorが置換するのは下記です
HostnameProcessor:extra.hostname
WebProcessor:extra.url、extra.ip、extra.http_method、extra.server、extra.referrer
IntrospectionProcessor:extra.file、extra.line、extra.class、extra.function

(4) 再び/sample/config/logging.phpファイル修正
今度は、'channels'=>'daily'要素(dailyチャンネル)を修正します

    'channels' => [
     ‥‥
        'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
            'days' => 0,
            'tap' => [App\Logging\SampleTap::class],
        ],
     ‥‥

dailyチャンネルは日付毎に1つのファイルにログを出力するチャンネルです。
どこに出力するか:path要素でstorage_path('logs/laravel.log')となっている場合、laravel-YYYY-MM-DD.logというファイル名形式のファイルが日付ごとにできます
何を、どのように出力するか:先ほどsingleチャンネルに設定したのと同じSampleTapクラスを設定しました
days要素は最大何日分のログファイルを保存しておくかです。0の場合、制限無しです

タイムゾーン設定

/sample/config/app.php修正

app.php
‥‥
'timezone' => 'Asia/Tokyo',
‥‥

timezone要素がUTCになっていると思うので、自分のタイムゾーンに変更します
これによりログに出力される日時、dailyチャンネルのファイル名が自分のタイムゾーンに合ったものになります

動作確認

http://localhost/laravelSample/sample/log

storage/logs配下を見るとログファイルができており、ログが出力されています

他のログチャンネル

Laravelには他にもログチャンネルが用意されています
下記リンク先の利用可能なチャンネルドライバという箇所に使用できるログチャンネル一覧があります
Laravel ログ
また、config/logging.php内のchannels配列を見ても使えるログチャンネルを確認できます
これらのログチャンネルを使うためのlogging.phpでの設定は
vendor/laravel/framework/src/Illuminate/Log/LogManager.phpのcreateチャンネル名Driverという名前のメソッド(createSlackDriverとかcreateSyslogDriverとか)を見るとわかります。
それらのメソッドは$configを引数に取り、MonologのHandlerクラスのコンストラクタに$configの要素を渡しています
MonologのHandlerクラスのコンストラクタに渡している$configの要素をlogging.phpで定義すれば使うことができます
MonologのHandlerは下記で確認できます
MonologのHandler

31
38
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
31
38