php - transacciones - Laravel 4-registro de consultas SQL
like laravel (6)
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(''/'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);
});
}
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/
.
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
- en mi archivo php view, hago una solicitud AJAX al servidor
La solicitud AJAX se recibe y ejecuta una consulta SQL Postgres parametrizada SIN PROCESAR (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?
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
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
});
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(''/'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);
});
}
Gracias a Jeemusu responden por un poco acerca de insertar los enlaces en la declaración preparada.
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 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(''/'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);
});
}
Si bien la respuesta aceptada es correcta, esta respuesta explica cómo actualizar el https://github.com/loic-sharma/profiler 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 <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);
};
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 .