1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Laravel6】ログをDBに出力(Monologを使う)

Last updated at Posted at 2021-10-11

Laravel6でArtisanコマンド作成し、そのArtisanコマンドをバッチで実行するような実装をしていました。
ログ出力をlaravel.logではなく、DBに出力する必要があったため、Laravelに標準でインストールされているMonologというパッケージを利用しました。

バージョン:Laravel 6.20.32

作業内容

  • マイグレーションファイル、モデルの作成
  • app/Loggers/DbMonologHandler.phpの作成
  • config/logging.phpにチャネルを追加
  • .envに追記
  • Artisanコマンドにログを記述

マイグレーションファイル、モデルの作成

ログ出力先のテーブルを作成します。
今回はd_logsというテーブルを作成。DLogモデルを作成し、マイグレーションも一緒に作成します。

php artisan make:model DLog --migration

モデルの記述

使用するテーブルを記載します。(省略した場合、モデル名DLogの場合、d_logsテーブルが使用されるので、省略可能。)
すべてのカラムに値の代入可能とするので、protected $guarded = [];とします。

<?php

namespace App\models;

use Illuminate\Database\Eloquent\Model;

class DLog extends Model
{
    protected $table = 'd_logs';
    protected $guarded = [];
}

マイグレーションの記述

  • id
  • level(debugなら100、errorなら400など)
  • level_name(INFOやERRORなど)
  • message(エラーメッセージなど)

他に必要なカラムがあれば適宜追加してください。

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class DLogsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('d_logs', function(Blueprint $table)
		{
            $table->bigIncrements('id');
            $table->text('level')->nullable();
            $table->text('level_name')->nullable();
            $table->text('message')->nullable();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('d_logs');
    }
}

app/Loggers/DbMonologHandler.phpの作成

今回出力する'level', 'level_name', 'message'を配列$dataに入れてあげます。

<?php

namespace App\Loggers;

use Illuminate\Support\Facades\DB;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Logger;
use App\Models\DLog;
use Log;

class DbMonologHandler extends AbstractProcessingHandler
{
    public function __construct(string $table, string $connection, $level = Logger::DEBUG, $bubble = true)
    {
        $this->table = $table;
        $this->connection = $connection;
        parent::__construct($level, $bubble);
    }

    protected function write(array $record): void
    {
        $data = [
            'message' => $record['message'],
            'level' => $record['level'],
            'level_name' => $record['level_name'],
        ];
        DLog::insert($data);
    }
}

config/logging.phpにチャネルを追加

既存の他のチャネルと同様の記述で、チャネルを追加します。(今回は'db'という名前で追加)

::classは、クラス名を名前空間と一緒に返しています。

'handler_with'で接続先などを指定します。env関数の第二引数には、デフォルト値を記述しているので、.envファイルに記述がない場合、この第二引数の値が使われます。

db' => [
    'driver' => 'monolog',
    'handler' => DbMonologHandler::class,
    'handler_with' => [
        'table' => env('DB_LOG_TABLE', 'd_logs'),
        'connection' => env('DB_LOG_CONNECTION', env('DB_CONNECTION', 'mysql')),
    ],
],

チャネルの一番上、stackに記載のチャネルにログが出力されるので、作成した'db'チャネルを追記します。

'channels' => [
    'stack' => [
        'driver' => 'stack',
        'channels' => ['single', 'db'],
        'ignore_exceptions' => false,
    ],

.envに追記

.envファイルに下記を追記。(書かない場合は、logging.phpのenv関数の第二引数の値が使われる。)

DB_LOG_TABLE=d_logs
DB_LOG_CONNECTION=mysql

Artisanコマンドにログを記述

今回は、特定のArtisanコマンドを実行した際に、ログがDBに出力されるようにしたいので、ArtisanコマンドにLogファサードで記述します。今回はバッチでデータをインポートしているので、

  • インポート開始
  • インポート完了
  • エラーメッセージ
  • ロールバック完了

などのログを出力しています。

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Services\UpsertAllByCsvService;
use Log;
use DB;

class ImportOrderDataSetByCsv extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'ImportOrderDataSetByCsv';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Upsert tables concerned about orders';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        Log::info('インポート開始');
        DB::beginTransaction();
        try {
            UpsertAllByCsvService::getOrdersDataByCsv('test');
            UpsertAllByCsvService::getOrderDetailsDataByCsv('test');
            UpsertAllByCsvService::getShippingsDataByCsv('test');
            UpsertAllByCsvService::getShipmentItemsDataByCsv('test');
            DB::commit();
            Log::info('インポート完了');
        } catch (\Exception $e) {
            DB::rollback();
            Log::error($e->getMessage());
            Log::info('ロールバック完了');
        }
    }
}

このArtisanコマンドをTinkerで実行すると、d_logsテーブルにレコードが追加されました!

ロールバックのタイミングに注意。ログテーブルのidが飛んでいる場合、ログは生成されているのに、そのログ出力も含めてロールバックされている可能性があります。

この記述だと、DbMonologHandlerで出力されるログは、laravel.logにも出力されます。

DBにのみ出力したい場合は、logging.phpのチャネル設定にて、stackには'db'を記載せず、
ログファサードを使う時に、Log::channel('db')->info('インポート開始');のように記述してください。

参考

https://qiita.com/kd9951/items/35b0a0c4e16353078b70
https://qiita.com/hirorin/items/409a66e63bb3b16245eb

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?