📝

【Laravel】実行SQLをデフォルト以外のログファイルに出力する方法

2022/07/31に公開

はじめに

本記事では、Laravelで実行されるSQLをログファイルで出力する方法について解説します。
また、デフォルトのログファイルとは別にstorage/logs配下にsql-yyyy-mm-dd.logファイルを作成して出力します。

サービスプロバイダーを作成

設定を登録するためのサービスプロバイダーを作成します。

$ php artisan make:provider DataBaseQueryServiceProvider

app/Providers配下にDataBaseQueryServiceProvider.phpが作成されることを確認します。

サービスプロバイダーを登録

config/app.phpに先ほど作成したDataBaseQueryServiceProvider.phpを登録します。
以下のように編集します。

app.php
    'providers' => [
	~ 中略 ~
        App\Providers\DataBaseQueryServiceProvider::class,
    ],

サービスプロバイダーを編集

app/Providers/DataBaseQueryServiceProvider.phpを以下のように編集します。

DataBaseQueryServiceProvider.php

<?php

namespace App\Providers;

use Carbon\Carbon;
use DateTime;
use Illuminate\Database\Events\TransactionBeginning;
use Illuminate\Database\Events\TransactionCommitted;
use Illuminate\Database\Events\TransactionRolledBack;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\ServiceProvider;

class DataBaseQueryServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        if (config('logging.sql.enable') === false) {
            return;
        }

        DB::listen(function ($query): void {
            $sql = $query->sql;

            foreach ($query->bindings as $binding) {
                if (is_string($binding)) {
                    $binding = "'{$binding}'";
                } elseif (is_bool($binding)) {
                    $binding = $binding ? '1' : '0';
                } elseif (is_int($binding)) {
                    $binding = (string) $binding;
                } elseif ($binding === null) {
                    $binding = 'NULL';
                } elseif ($binding instanceof Carbon) {
                    $binding = "'{$binding->toDateTimeString()}'";
                } elseif ($binding instanceof DateTime) {
                    $binding = "'{$binding->format('Y-m-d H:i:s')}'";
                }

                $sql = preg_replace('/\\?/', $binding, $sql, 1);
            }

            Log::channel('sql')->debug('SQL', ['sql' => $sql, 'time' => "{$query->time} ms"]);
        });

        Event::listen(TransactionBeginning::class, function (TransactionBeginning $event): void {
            Log::channel('sql')->debug('START TRANSACTION');
        });

        Event::listen(TransactionCommitted::class, function (TransactionCommitted $event): void {
            Log::channel('sql')->debug('COMMIT');
        });

        Event::listen(TransactionRolledBack::class, function (TransactionRolledBack $event): void {
            Log::channel('sql')->debug('ROLLBACK');
        });
    }
~ 以下略 ~

ログの設定を追加

app/config/logging.phpを以下のように編集します。

logging.php
return [
    ~ 中略 ~
    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'channels' => ['single', 'sql'], // デフォルトでは'single'のみ
            'ignore_exceptions' => false,
        ],
    ~ 中略 ~
        'sql' => [
            'driver' => 'daily',  // 日別
            'path' => storage_path('logs/sql.log'), // 出力先
            'level' => 'debug', // ログレベル
            'days' => 14, // 保存期間
        ],
    ],
    'sql' => [
        'enable' => env('LOG_SQL_ENABLE', true),
    ],
];  

設定を反映

configのキャッシュをクリアして設定を反映してください。

$ php artisan config:clear

実行&確認

SQLが発行される処理を実行すると、app/storage/配下にsql-yyyy-mm-dd.logファイルが作成され、実行されたSQLが出力されていることがわかると思います。

[2022-07-31 09:05:27] development.DEBUG: SQL {"sql":"select * from `users` where `email` = 'test@example.com' limit 1","time":"8.13 ms"} 
[2022-07-31 09:05:28] development.DEBUG: SQL {"sql":"select * from `users` where `id` = 1 limit 1","time":"8.54 ms"} 
[2022-07-31 09:05:28] development.DEBUG: SQL {"sql":"select * from `memos` where `user_id` = 1","time":"1.31 ms"} 
[2022-07-31 09:05:42] development.DEBUG: SQL {"sql":"select * from `users` where `id` = 1 limit 1","time":"7.62 ms"} 
[2022-07-31 09:05:42] development.DEBUG: SQL {"sql":"insert into `memos` (`user_id`, `title`, `body`, `updated_at`, `created_at`) values (1, 'メモ', 'メモ', '2022-07-31 09:05:42', '2022-07-31 09:05:42')","time":"3.26 ms"} 
[2022-07-31 09:05:43] development.DEBUG: SQL {"sql":"select * from `users` where `id` = 1 limit 1","time":"11.18 ms"} 
[2022-07-31 09:05:43] development.DEBUG: SQL {"sql":"select * from `memos` where `user_id` = 1","time":"1.96 ms"} 

参考

https://readouble.com/laravel/8.x/ja/logging.html
https://qiita.com/ucan-lab/items/753cb9d3e4ceeb245341

Discussion