Laravel 4 – протоколирование SQL-запросов

Уже есть несколько вопросов относительно регистрации SQL-запроса в Laravel 4. Но я пробовал почти все из них, и он все еще не работает так, как я хочу.

Вот моя ситуация

  1. в моем файле php view, я делаю запрос AJAX на сервер
  2. Запрос AJAX принимается и запускает параметризованный RAW-запрос Postgres SQL (например,

    DB :: select ('select * from my_table где id =?', Array (1))

Если я использую

Event::listen('illuminate.query', function($sql) { Log::error($sql); }); 

Я просто получаю «select * from my_table, где id =?» как сообщение журнала без фактического заполнения идентификатора.

Если я использую

 $queries = DB::getQueryLog(); $last_query = end($queries); Log::error(print_r($last_query, true)); 

У меня до сих пор нет окончательного SQL-запроса с заполненным идентификатором.

Наконец, если я использую инструмент ведения журнала, например https://github.com/loic-sharma/profiler, он ничего не отображает, так как я делаю запрос AJAX.

Я исчерпал свои возможности? Есть ли еще лучший способ?

Related of "Laravel 4 – протоколирование SQL-запросов"

Вот что я сейчас использую для регистрации sql-запросов. Вы должны убрать это в свой основной файл маршрутов, а затем добавить «log» => true в конфигурацию своей базы данных.

 if (Config::get('database.log', false)) { Event::listen('illuminate.query', function($query, $bindings, $time, $name) { $data = compact('bindings', 'time', 'name'); // Format binding data for sql insertion foreach ($bindings as $i => $binding) { if ($binding instanceof \DateTime) { $bindings[$i] = $binding->format('\'Ymd H:i:s\''); } else if (is_string($binding)) { $bindings[$i] = "'$binding'"; } } // Insert bindings into query $query = str_replace(array('%', '?'), array('%%', '%s'), $query); $query = vsprintf($query, $bindings); Log::info($query, $data); }); } 

Благодаря Jeemusu ответьте на вопрос о вставке привязок в подготовленный оператор.

Вы можете найти привязки, передав $bindings в качестве второго параметра функции Event.

 Event::listen('illuminate.query', function($sql, $bindings, $time){ echo $sql; // select * from my_table where id=? print_r($bindings); // Array ( [0] => 4 ) echo $time; // 0.58 // To get the full sql query with bindings inserted $sql = str_replace(array('%', '?'), array('%%', '%s'), $sql); $full_sql = vsprintf($sql, $bindings); }); 

В Laravel 3.x я думаю, что прослушиватель событий был вызван laravel.query

Продолжая на @Collin Джеймс ответить .

Если вы хотите войти в отдельный файл только для sql, вы можете сделать это с помощью этого:

 if (Config::get('database.log', false)) { Event::listen('illuminate.query', function($query, $bindings, $time, $name) { $data = compact('bindings', 'time', 'name'); // Format binding data for sql insertion foreach ($bindings as $i => $binding) { if ($binding instanceof \DateTime) { $bindings[$i] = $binding->format('\'Ymd H:i:s\''); } else if (is_string($binding)) { $bindings[$i] = "'$binding'"; } } // Insert bindings into query $query = str_replace(array('%', '?'), array('%%', '%s'), $query); $query = vsprintf($query, $bindings); $log = new Logger('sql'); $log->pushHandler(new StreamHandler(storage_path().'/logs/sql-' . date('Ym-d') . '.log', Logger::INFO)); // add records to the log $log->addInfo($query, $data); }); } 

С этим в верхней части вашего файла:

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

Это будет записывать все ваши запросы в файл с именем sql-YYYY-mm-dd.log в storage/logs/ .

Хотя принятый ответ правилен, в этом ответе объясняется, как обновлять профилировщик loic-sharma при выполнении запросов Ajax с использованием jQuery. Используя этот подход, не нужно читать журналы файлов.

Шаг 1

Первая проблема заключается в отправке обновленных данных профилировщика клиенту по каждому запросу Ajax. Это можно решить, используя «после» события приложения Laravel.

Приложение / filters.php:

 App::after(function($request, $response) { // If it's a JsonResponse and the profiler is enabled, include it in the response. if($response instanceof \Illuminate\Http\JsonResponse && Profiler::isEnabled()) { $profiler = Profiler::getFacadeRoot(); $profilerJson = json_encode($profiler->render()); $content = substr($response->getContent(), 0, -1) . ',"profiler":' . $profilerJson . '}'; $response->setContent($content); } }); 

Фильтр App::after будет запускаться при каждом запросе Laravel. Первая строка закрытия выше, гарантирует, что она будет продолжаться только в том случае, если ответ имеет тип JsonResponse и включен профайлер. Если это так, отрисуйте профилировщик и добавьте HTML в объект JSON.

Примечание: этот код предполагает, что возвращаемый JSON является объектом. Поэтому он не будет работать для массивов: Response::json(array(1,2,3)) .

Шаг 2

Теперь, когда обновленный HTML-код профилировщика отправляется клиенту, мы должны обновить DOM с помощью нового HTML-кода профилировщика, используя javascript. Это должно происходить каждый раз, когда клиент получает ответ JSON. jQuery предоставляет глобальные обработчики событий Ajax, что идеально подходит для достижения этого.

 $(document).ajaxSuccess(function(event, request, settings) { try { json = jQuery.parseJSON(request.responseText); if(json.profiler) { renderProfiler(json.profiler); } } catch(error) { // Its not JSON. return; } }); 

Ниже приведен метод замены старого профайлера на новый:

 renderProfiler = function(data) { // Remove previous $anbu = $('.anbu'); $anbu.prev().remove(); // Removes <style> tag of profiler $anbu.next().next().remove(); // Removes the inline script tag of profiler $anbu.next().remove(); // Removes jQuery script tag by the profiler $anbu.remove(); // Removes the <div> tag of profiler $(document.body).append(data); }; 

Используй это

Теперь это так же просто, как и возвращаемые ответы:

 return Response::json(array( 'user' => Auth::user() )); 

Laravel добавит HTML-код профилировщика. Javascript поймает ответ JSON и обновит DOM. У вас будут SQL-запросы и тайминги прямо на веб-странице.

Заметка

Пока код проверен, может быть ошибка или два. Это также не совсем так, как я это делаю. Вместо отправки HTML в json-ответе я распространяю объект с фактическими данными из профилировщика. На стороне клиента я обрабатываю профилировщик с использованием шаблона уса .

Хотя вопрос был первоначально нацелен на Laravel 4, я все же оказался здесь через google, но я использую Laravel 5.

Есть новые способы для регистрации всех запросов в Laravel 5 с использованием Middleware , но если вы предпочитаете тот же подход, здесь тот же код, предоставленный Collin James, но работающий в Laravel 5

 if (Config::get('database.log', false)) { Event::listen('Illuminate\Database\Events\QueryExecuted', function($query) { $bindings = $query->bindings; $time = $query->time; $name = $query->connection->getName(); $data = compact('bindings', 'time', 'name'); // Format binding data for sql insertion foreach ($bindings as $i => $binding) { if ($binding instanceof \DateTime) { $bindings[$i] = $binding->format('\'Ymd H:i:s\''); } else if (is_string($binding)) { $bindings[$i] = "'$binding'"; } } // Insert bindings into query $query = str_replace(array('%', '?'), array('%%', '%s'), $query->sql); $query = vsprintf($query, $bindings); Log::info($query, $data); }); } 

Это то, что я использовал:

 DB::listen(function ($query, $bindings, $time, $connection) { $fullQuery = vsprintf(str_replace(array('%', '?'), array('%%', '%s'), $query), $bindings); $result = $connection . ' (' . $time . '): ' . $fullQuery; dump($result); // You can of course log the $result });