📝
【Laravel】実行SQLをデフォルト以外のログファイルに出力する方法
はじめに
本記事では、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"}
参考
Discussion