Log all Eloquent Queries

PHP:7.2

Laravel:5.7

在開發的過程中,很常會遇到一些奇怪的資料庫問題,可能是從 DB 拉出來的資料有錯、可能直接噴 SQL 的 error,如果 SQL query 很複雜,更難找到問題的原因。

因此,適當的紀錄相關資訊在開發上是非常有幫助的,而資料庫相關的問題,最直接的做法就是 log SQL query ,通常只要找出完整的 SQL query,很快就可以找到問題的原因了。

Create ServiceProvider

Log SQL query 這件事應該要是全域的,因此可以直接建立一個專門處理這件事的 ServiceProvider

利用 Artisan 建立 QueryLogServiceProvider

./artisan make:provider QueryLogServiceProvider

Register QueryLogServiceProvider
config/app.php

/*
 * Application Service Providers...
 */
App\Providers\QueryLogServiceProvider::class,

Format Query

Laravel Eloquent 中的 SQL query 都有做資料的 escape,因此資料會分成 Escape Query(變數都會被 ? 取代) 跟 Binding Data,如果想看的仔細一點,可以自己手動針對資料做一些調整,變成可以直接貼在 command 的 SQL query。

app/Providers/QueryLogServiceProvider.php

public function boot()
{
    // Listening for query events
    \DB::listen(function ($query) {
        // Escape Query
        $sql = $query->sql;
        // Binding Data
        $bindings = $query->bindings;
        // Spend Time
        $time = $query->time;

        // 針對 Binding 資料進行格式的處理
        // 例如字串就加上引號
        foreach ($bindings as $index => $binding) {
            if (is_bool($binding)) {
                $bindings[$index] = ($binding) ? ('1') : ('0');
            } elseif (is_string($binding)) {
                $bindings[$index] = "'$binding'";
            }
        }

        // 依據將 ? 取代成 Binding Data
        $sql = preg_replace_callback('/\?/', function () use (&$bindings) {
            return array_shift($bindings);
        }, $sql);

        // 寫入 storage/logs/laravel.log
        \Log::info($sql);
    });
}

完成之後就可以在 storage/logs/laravel.log 看到相關的 SQL query log 了。

Categories: Laravel