Laravel 4 - протоколирование SQL-запросов
Уже есть несколько вопросов относительно регистрации SQL-запроса в Laravel 4. Но я пробовал почти все из них, и он все еще не работает так, как я хочу.
Здесь моя ситуация
- в моем файле php view, я делаю запрос AJAX на сервер
-
Запрос AJAX принимается и запускает параметр запроса Postgres SQL, зависящий от RAW (например,
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.
Я исчерпал свои возможности? Есть ли еще лучший способ?
Ответы
Ответ 1
Вот что я сейчас использую для регистрации запросов 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('\'Y-m-d 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 ответить за бит о вставке привязок в подготовленный оператор.
Ответ 2
Вы можете найти привязки, передав $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
Ответ 3
Продолжение на @Collin James отвечает.
Если вы хотите войти в отдельный файл только для 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('\'Y-m-d 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('Y-m-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/
.
Ответ 4
В то время как принятый ответ верен, в этом ответе объясняется, как обновлять loic-sharma profiler при выполнении запросов Ajax с использованием jQuery. Используя этот подход, не нужно читать журналы файлов.
Шаг 1
Первая проблема заключается в отправке обновленных данных профилировщика клиенту по каждому запросу Ajax. Это можно решить, используя "после" события приложения Laravel.
Приложение/filters.php:
App::after(function($request, $response)
{
// If it 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-ответе я распространяю объект с фактическими данными из профилировщика. На стороне клиента я обрабатываю профилировщик с помощью шаблона усов.
Ответ 5
Пока вопрос был первоначально нацелен на Laravel 4, я все еще попадал сюда через google, но я использую Laravel 5.
Появились новые способы регистрации всех запросов в Laravel 5 с использованием Middleware, но если вы предпочитаете тот же подход, здесь приведен один и тот же код by 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('\'Y-m-d 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);
});
}
Ответ 6
Что я использовал:
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
});