Laravel和Lumen开启SQL日志记录

Laravel并不会默认打印sql,所以需要我们自己来设置。

1、临时打印SQL

DB::enableQueryLog();
查询操作
Log::debug(DB::getQueryLog());

2、自动记录SQL日志

方法1:监听 QueryExecuted 事件

此事件是由 Illuminate\Database 提供,并且当你发起SQL的时候,此事件是被触发的,只是没有对应的监听器罢了。
在 app/Providers/EventServicePorvider.php 文件中 添加要注册的事件

use Illuminate\Database\Events\QueryExecuted;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        'Illuminate\Database\Events\QueryExecuted' => [
            'App\Listeners\QueryListener',
        ],
    ];
}

执行 命令 php artisan event:generate

在 App\Listeners\QueryListener 文件的 handle 方法中编写记录 sql 的业务逻辑,如:

public function handle(QueryExecuted $event)
{
    try{
        if (env('APP_DEBUG') == true) {
            $sql = str_replace("?", "'%s'", $event->sql);
            foreach ($event->bindings as $i => $binding) {
                if ($binding instanceof DateTime) {
                    $event->bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
                } else {
                    if (is_string($binding)) {
                        $event->bindings[$i] = "'$binding'";
                    }
                }
            }
            $log = vsprintf($sql, $event->bindings);
            $log = $log.'  [ RunTime:'.$event->time.'ms ] ';
            (new Logger('sql'))->pushHandler(new RotatingFileHandler(storage_path('logs/sql/sql.log')))->info($log);
        }
    }catch (Exception $exception){

    }
}

日志文件默认保存在 storage/logs/sql/ 目录下

方法2:

在 app/providers/AppServicesProviders.php 文件的 boot 方法编写如下代码

use Illuminate\Support\Facades\DB;

DB::listen(
    function ($sql) {
        foreach ($sql->bindings as $i => $binding) {
            if ($binding instanceof \DateTime) {
                $sql->bindings[$i] = $binding->format('Y-m-d H:i:s');
            } else {
                if (is_string($binding)) {
                    $sql->bindings[$i] = "'$binding'";
                }
            }
        }
 
        // Insert bindings into query
        $query = str_replace(array('%', '?'), array('%%', '%s'), $sql->sql);
 
        $query = vsprintf($query, $sql->bindings);
 
        // Save the query to file
        $logFile = fopen(
            storage_path('logs' . DIRECTORY_SEPARATOR . date('Y-m-d') . '_query.log'),
            'a+'
        );
        fwrite($logFile, date('Y-m-d H:i:s') . ': ' . $query . PHP_EOL);
        fclose($logFile);
    }
);

或者

DB::listen(function ($query) {
    $tmp = str_replace('?', '"'.'%s'.'"', $query->sql);
    $qBindings = [];
    foreach ($query->bindings as $key => $value) {
        if (is_numeric($key)) {
            $qBindings[] = $value;
        } else {
            $tmp = str_replace(':'.$key, '"'.$value.'"', $tmp);
        }
    }
    $tmp = vsprintf($tmp, $qBindings);
    $tmp = str_replace("\\", "", $tmp);
    \Log::info(' execution time: '.$query->time.'ms; '.$tmp."\n\n\t");
});

我们来看一下源码

此处 Facades\DB 代表我的 Illuminate\Database\MySqlConnection ,因为我也的是MySQL数据库,在它的基类 Connection 中有个 listen 方法:

public function listen(Closure $callback)
{
    if (isset($this->events)) {
        $this->events->listen(Events\QueryExecuted::class, $callback);
    }
}

就是将闭包 $callback 监听 Events\QueryExecuted 事件,也就是方法1的 Illuminate\Database\Events\QueryExecuted 事件,然后传入到闭包中的参数 $sql 或 q u e r y 1 query 就是方法1的 event。

发布了412 篇原创文章 · 获赞 25 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/raoxiaoya/article/details/103610239