Подтвердить что ты не робот

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.

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

4b9b3361

Ответ 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
});