Как выполнить запрос в Laravel 5? DB :: getQueryLog () Возвращает пустой массив


173

Я пытаюсь просмотреть журнал для запроса, но DB::getQueryLog()просто возвращает пустой массив:

$user = User::find(5);
print_r(DB::getQueryLog());

результат

Array
(
)

Как я могу просмотреть журнал для этого запроса?


Laravel Debugbar - отличный инструмент для регистрации запросов. У этого также есть много других удивительных особенностей.
Тотемедли

Ответы:


256

По умолчанию журнал запросов отключен в Laravel 5: https://github.com/laravel/framework/commit/e0abfe5c49d225567cb4dfd56df9ef05cc297448

Вам нужно будет включить журнал запросов, позвонив:

DB::enableQueryLog();

или зарегистрируйте прослушиватель событий:

DB::listen(
    function ($sql, $bindings, $time) {
        //  $sql - select * from `ncv_users` where `ncv_users`.`id` = ? limit 1
        //  $bindings - [5]
        //  $time(in milliseconds) - 0.38 
    }
);  

Некоторые советы

1. Несколько соединений с БД

Если у вас есть более одного подключения к БД, вы должны указать, какое соединение регистрировать

Чтобы включить журнал запросов для my_connection:

DB::connection('my_connection')->enableQueryLog();

Чтобы получить журнал запросов для my_connection:

print_r(
   DB::connection('my_connection')->getQueryLog()
);

2. Где включить журнал запросов?

Для жизненного цикла HTTP-запроса вы можете включить журнал запросов в handleметоде некоторого BeforeAnyDbQueryMiddleware промежуточного программного обеспечения, а затем получить выполненные запросы в terminateметоде того же промежуточного программного обеспечения.

class BeforeAnyDbQueryMiddleware
{
    public function handle($request, Closure $next)
    {
        DB::enableQueryLog();
        return $next($request);
    }

    public function terminate($request, $response)
    {
        // Store or dump the log data...
        dd(
            DB::getQueryLog()
        );
    }
}

Цепочка промежуточного программного обеспечения не будет работать для команд кустарного производства, поэтому для выполнения CLI вы можете включить журнал запросов в artisan.start событий.

Например, вы можете положить его в bootstrap/app.phpфайл

$app['events']->listen('artisan.start', function(){
    \DB::enableQueryLog();
});

3. Память

Laravel хранит все запросы в памяти. Поэтому в некоторых случаях, например при вставке большого количества строк или при длительном выполнении задания с большим количеством запросов, это может привести к тому, что приложение будет использовать избыточную память.

В большинстве случаев вам понадобится журнал запросов только для отладки, и в этом случае я бы порекомендовал включить его только для разработки.

if (App::environment('local')) {
    // The environment is local
    DB::enableQueryLog();
}

Ссылки


6
Если ваша система использует более одного соединения с БД, вы должны указать его, в противном случае он может вернуть пустой массив:\DB::connection('myconnection')->enableQueryLog(); print_r(\DB::connection('myconnection')->getQueryLog());
Диана Р.

Разместите свой комментарий как ответ @DianaR.
Нарендрасинг Сисодиа


Как включить запись в журнал Eloquent "NameController :: create ();" заявление?
Рубен Руис

2
Обратите внимание, что в Laravel 5.4 DB::listenфункция обратного вызова имеет другую подпись. Это больше похоже на это: DB::listen(function($query) { $sql = $query->sql; $bindings = $query->bindings; $time = $query->time; ... });
racl101

45

Если все, что вас действительно волнует, это фактический запрос (последний запущенный) для целей быстрой отладки:

DB::enableQueryLog();

# your laravel query builder goes here

$laQuery = DB::getQueryLog();

$lcWhatYouWant = $laQuery[0]['query']; # <-------

# optionally disable the query log:
DB::disableQueryLog();

сделать print_r()ON , $laQuery[0]чтобы получить полный запрос, в том числе и креплений. ( $lcWhatYouWantпеременная, указанная выше, будет заменена на?? )

Если вы используете что-то отличное от основного подключения mysql, вам нужно использовать это вместо:

DB::connection("mysql2")->enableQueryLog();

DB::connection("mysql2")->getQueryLog();

(с вашим именем подключения, где "mysql2")


1
Куда идет этот код? (5.4) Я пробовал контроллер, модель и искал промежуточное ПО, не зная, где его выполнить, прежде чем я получу ошибку БД.
бля

Если вы получаете ошибку при выполнении запроса, который останавливает выполнение, ошибка должна сообщить вам, в чем проблема. Если у вас отключены ошибки, вы можете проверить журнал ошибок в / storage / log / laravel или что-то в этом роде. (Сейчас я не за компьютером) Если вы говорите, что получаете ошибку при выполнении кода, который я предложил в своем ответе, убедитесь, что вы включаете фасад БД, где бы вы ни выполняли код. Не уверен, что вы пытаетесь сделать, но контроллер звучит как самый правильный из упомянутых вами вариантов. (Я обычно запускать запросы в отдельно вспомогательные классы)
Skeets

15

Вы должны сначала включить ведение журнала запросов

DB::enableQueryLog();

Тогда вы можете получить журналы запросов просто:

dd(DB::getQueryLog());

Было бы лучше, если вы включите ведение журнала запросов перед запуском приложения, что можно сделать в BeforeMiddleware, а затем получить выполненные запросы в AfterMiddleware.


14

Поместите это в файл rout.php:

\Event::listen('Illuminate\Database\Events\QueryExecuted', function ($query) {
    echo'<pre>';
    var_dump($query->sql);
    var_dump($query->bindings);
    var_dump($query->time);
    echo'</pre>';
});

Представлено msurguy, исходный код на этой странице . Этот код исправления для laravel 5.2 вы найдете в комментариях.


Немного грязно, но +1 для $ query-> bindings и $ query-> time hints
Паоло Стефан,

Ухоженная! Использование этого показывает результаты в представлении, прямо там, где происходит запрос!
Чарльз Вуд

11

Как видно из Laravel 5.2, замыкание DB::listenполучает только один параметр.

Итак, если вы хотите использовать DB::listenв Laravel 5.2, вы должны сделать что-то вроде:

DB::listen(
    function ($sql) {
        // $sql is an object with the properties:
        //  sql: The query
        //  bindings: the sql query variables
        //  time: The execution time for the query
        //  connectionName: The name of the connection

        // To save the executed queries to file:
        // Process the sql and the bindings:
        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);
    }
);

Для более старого Laravel я добавил свое решение в stackoverflow.com/a/44920198/3823826
Csongor Halmai


5

Используйте toSql()вместо этого get()так:

$users = User::orderBy('name', 'asc')->toSql();
echo $users;
// Outputs the string:
'select * from `users` order by `name` asc'

2

(Laravel 5.2) Я считаю, что самый простой способ - просто добавить одну строку кода для мониторинга SQL-запросов:

\DB::listen(function($sql) {var_dump($sql); });

1

В продолжение, по- видимому, с Laravel 5.2, замыкание в DB :: listen получает только один параметр ... ответ выше: вы можете поместить этот код в скрипт Middleware и использовать его в маршрутах.

Дополнительно:

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$log = new Logger('sql');
$log->pushHandler(new StreamHandler(storage_path().'/logs/sql-' . date('Y-m-d') . '.log', Logger::INFO));

// add records to the log
$log->addInfo($query, $data);

какую часть следует поместить в промежуточное ПО? который в маршрутах?
user1016265

1

Этот код для:

  • Ларавел 5.2
  • Записать заявления в базу данных MySQL

Вот код, который основан на ответе @milz:

    DB::listen(function($sql) {
        $LOG_TABLE_NAME = 'log';
        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);
        if(stripos($query, 'insert into `'.$LOG_TABLE_NAME.'`')===false){
            $toLog = new LogModel();
            $toLog->uId = 100;
            $toLog->sql = $query;
            $toLog->save();
        }
    });

Ядром является if(stripos...строка, которая предотвращает рекурсию вставки insert into logоператора SQL в базу данных.


0

Я думаю, что ответ находится в этой статье: https://arjunphp.com/laravel-5-5-log-eloquent-queries/

быстро и просто добиться регистрации запросов.

Вам просто нужно добавить AppServiceProviderв bootметод обратный вызов для прослушивания запросов к БД:

namespace App\Providers;

use DB;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        DB::listen(function($query) {
            logger()->info($query->sql . print_r($query->bindings, true));
        });
    }
}

0

Предположим, вы хотите напечатать SQL-запрос следующих операторов.

$user = User::find(5);

Вам просто нужно сделать следующее:

DB::enableQueryLog();//enable query logging

$user = User::find(5);

print_r(DB::getQueryLog());//print sql query

Это напечатает последний выполненный запрос в Laravel.


-3

Для laravel 5 и далее использование только DB :: getQueryLog () не подойдет. По умолчанию в этом значение

 protected $loggingQueries = false;

измените это на

protected $loggingQueries = true; 

в файле ниже для регистрации запроса.

/vendor/laravel/framework/src/illuminate/Database/Connection.php 

И тогда мы можем использовать, DB::getQueryLog()где вы хотите напечатать запрос.


1
Это плохая идея, редактировать vendorфайлы. Они должны быть оригинальными.
shukshin.ivan

@ shukshin.ivan Да, не нужно редактировать файлы вендора, но чтобы получить точный запрос, мы должны отредактировать этот код на некоторое время, тогда мы сможем изменить его обратно.
Рупали Пемаре
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.