Laravel 4 – registro de consultas SQL

Ya hay varias preguntas con respecto a registrar la consulta SQL en Laravel 4. Pero he probado casi todas y todavía no funciona de la manera que quiero.

Esta es mi situación

  1. en mi archivo php view, hago una solicitud AJAX al servidor
  2. Se recibe la solicitud AJAX y se ejecuta una consulta SQL Postgres parametrizada en formato RAW (por ejemplo,

    DB :: select (‘select * from my_table where id =?’, Array (1))

Si uso

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

Acabo de recibir “select * from my_table where id =?” como el mensaje de registro sin el valor de ID realmente poblado.

Si uso

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

Todavía no tengo la consulta SQL final con el ID rellenado.

Finalmente, si utilizo una herramienta de registro como https://github.com/loic-sharma/profiler , no muestra nada ya que estoy haciendo una solicitud de AJAX.

¿He agotado mis opciones? ¿Hay alguna otra manera mejor?

Esto es lo que estoy usando actualmente para el registro de consultas sql. Debería poder colocar esto en su archivo de rutas principales y luego agregar ‘log’ => verdadero en la configuración de su base de datos.

 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); }); } 

Gracias a Jeemusu responden por un poco acerca de insertar los enlaces en la statement preparada.

Debería poder encontrar los enlaces pasando $bindings como el segundo parámetro de la función Evento.

 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); }); 

En Laravel 3.x, creo que el oyente del evento se llamaba laravel.query

Continuando con la respuesta de @Collin James .

Si desea iniciar sesión en un archivo separado solo para sql, puede hacerlo con esto:

 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); }); } 

Con esto en la parte superior de su archivo:

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

Esto registrará todas sus consultas en un archivo llamado sql-YYYY-mm-dd.log en storage/logs/ .

Si bien la respuesta aceptada es correcta, esta respuesta explica cómo actualizar el generador de perfiles loic-sharma al realizar solicitudes Ajax utilizando jQuery. Usando este enfoque uno no necesita leer registros de archivos.

Paso 1

El primer problema es enviar los datos actualizados del perfilador al cliente en cada solicitud de Ajax. Esto se puede resolver usando los eventos “posteriores” de la aplicación Laravel.

app / 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); } }); 

El filtro App::after se ejecutará en cada solicitud de Laravel. La primera línea del cierre anterior, se asegura de que solo continuará si la respuesta es de tipo JsonResponse y el generador de perfiles está habilitado. Si ese es el caso, renderice el generador de perfiles y anexe el HTML al objeto JSON.

Nota: este código supone que el JSON devuelto es un objeto. Por lo tanto, fallará en las matrices: Response::json(array(1,2,3)) .

Paso 2

Ahora que el HTML del generador de perfiles actualizado se está enviando al cliente, debemos actualizar el DOM con el nuevo HTML del generador de perfiles utilizando javascript. Esto debería suceder cada vez que el cliente recibe una respuesta JSON. jQuery proporciona controladores de eventos Ajax globales, lo cual es perfecto para lograr esto.

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

Aquí hay un método para reemplazar el viejo generador de perfiles con el nuevo:

 renderProfiler = function(data) { // Remove previous $anbu = $('.anbu'); $anbu.prev().remove(); // Removes  

Usándolo

Ahora es tan simple como devolver respuestas como:

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

Laravel agregará el generador de perfiles HTML. El javascript detectará la respuesta JSON y actualizará el DOM. Tendrás las consultas y los tiempos de SQL directamente en la página web.

Nota

Mientras se prueba el código, puede haber un error o dos. Esta tampoco es exactamente la forma en que lo hago. En lugar de enviar el HTML en la respuesta json, extiendo el objeto con los datos reales del generador de perfiles. En el lado del cliente, renderizo el perfilador usando una plantilla de bigote .

Si bien la pregunta se orientó originalmente a Laravel 4, aún terminé aquí a través de Google, pero estoy usando Laravel 5.

Hay nuevas maneras de registrar todas las consultas en Laravel 5 usando Middleware , pero si prefiere el mismo enfoque, aquí está el mismo código provisto por Collin James pero que funciona para 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); }); } 

Eso es lo que he estado usando:

 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 });