Comment faire exécuter la requête dans Laravel 5? DB :: getQueryLog () renvoyant un tableau vide

173

J'essaie d'afficher le journal pour une requête, mais DB::getQueryLog()je renvoie simplement un tableau vide:

$user = User::find(5);
print_r(DB::getQueryLog());

Résultat

Array
(
)

Comment afficher le journal de cette requête?

Arsen
la source
Laravel Debugbar est un excellent outil pour enregistrer les requêtes. Il a également de nombreuses autres fonctionnalités impressionnantes.
totymedli

Réponses:

256

Par défaut, le journal des requêtes est désactivé dans Laravel 5: https://github.com/laravel/framework/commit/e0abfe5c49d225567cb4dfd56df9ef05cc297448

Vous devrez activer le journal des requêtes en appelant:

DB::enableQueryLog();

ou enregistrez un écouteur d'événements:

DB::listen(
    function ($sql, $bindings, $time) {
        //  $sql - select * from `ncv_users` where `ncv_users`.`id` = ? limit 1
        //  $bindings - [5]
        //  $time(in milliseconds) - 0.38 
    }
);  

Quelques conseils

1. Connexions DB multiples

Si vous disposez de plusieurs connexions DB, vous devez spécifier la connexion à enregistrer

Pour activer le journal des requêtes pour my_connection:

DB::connection('my_connection')->enableQueryLog();

Pour obtenir le journal des requêtes pour my_connection:

print_r(
   DB::connection('my_connection')->getQueryLog()
);

2. Où activer le journal des requêtes?

Pour un cycle de vie de requête HTTP, vous pouvez activer le journal des requêtes dans la handleméthode de certains BeforeAnyDbQueryMiddleware middleware , puis récupérer les requêtes exécutées dans la terminateméthode du même middleware.

class BeforeAnyDbQueryMiddleware
{
    public function handle($request, Closure $next)
    {
        DB::enableQueryLog();
        return $next($request);
    }

    public function terminate($request, $response)
    {
        // Store or dump the log data...
        dd(
            DB::getQueryLog()
        );
    }
}

La chaîne d'un middleware ne fonctionnera pas pour les commandes artisanales, vous pouvez donc activer le journal des requêtes dans l' artisan.startécouteur d'événements pour l'exécution de la CLI .

Par exemple, vous pouvez le mettre dans le bootstrap/app.phpfichier

$app['events']->listen('artisan.start', function(){
    \DB::enableQueryLog();
});

3. Mémoire

Laravel garde toutes les requêtes en mémoire. Ainsi, dans certains cas, comme lors de l'insertion d'un grand nombre de lignes ou lors d'un travail de longue durée avec beaucoup de requêtes, cela peut amener l'application à utiliser un excès de mémoire.

Dans la plupart des cas, vous n'aurez besoin du journal des requêtes que pour le débogage, et si tel est le cas, je vous recommande de l'activer uniquement pour le développement.

if (App::environment('local')) {
    // The environment is local
    DB::enableQueryLog();
}

Références

Marty Aghajanyan
la source
6
Si votre système utilise plus d'une connexion db, vous devez le spécifier, sinon il pourrait renvoyer un tableau vide:\DB::connection('myconnection')->enableQueryLog(); print_r(\DB::connection('myconnection')->getQueryLog());
Diana R.
Postez votre commentaire en tant que réponse @DianaR.
Narendrasingh Sisodia
1
Pour Laravel 5.2, voir: laravel.com/docs/5.2/database#listening-for-query-events
Dmitri Chebotarev
Comment l'activer pour enregistrer Eloquent "NameController :: create ();" déclaration?
Rubén Ruíz
2
Notez que dans Laravel 5.4, la DB::listenfonction de rappel a une signature différente. C'est plus comme ça: DB::listen(function($query) { $sql = $query->sql; $bindings = $query->bindings; $time = $query->time; ... });
racl101
45

Si tout ce qui vous importe vraiment, c'est la requête réelle (la dernière exécution) à des fins de débogage rapide:

DB::enableQueryLog();

# your laravel query builder goes here

$laQuery = DB::getQueryLog();

$lcWhatYouWant = $laQuery[0]['query']; # <-------

# optionally disable the query log:
DB::disableQueryLog();

faites un print_r()on $laQuery[0]pour obtenir la requête complète, y compris les liaisons. (la $lcWhatYouWantvariable ci-dessus aura les variables remplacées par ??)

Si vous utilisez autre chose que la connexion principale mysql, vous devrez les utiliser à la place:

DB::connection("mysql2")->enableQueryLog();

DB::connection("mysql2")->getQueryLog();

(avec votre nom de connexion où "mysql2" est)

Skeets
la source
1
où va ce code? (5.4) J'ai essayé le contrôleur, le modèle et j'ai regardé dans le middleware, je ne sais pas où l'exécuter avant d'obtenir l'erreur db.
blamb
Si vous obtenez une erreur lors de l'exécution de la requête qui arrête l'exécution, l'erreur devrait vous indiquer le problème. Si les erreurs sont désactivées, vous pouvez consulter le journal des erreurs dans / storage / log / laravel ou quelque chose comme ça. (Je ne suis pas sur mon ordinateur pour le moment) Si vous dites que vous obtenez une erreur lors de l'exécution du code que j'ai suggéré dans ma réponse, assurez-vous d'inclure la façade DB partout où vous exécutez le code. Je ne sais pas ce que vous essayez de faire, mais le contrôleur sonne comme la plus correcte des options que vous avez mentionnées. (J'exécute généralement des requêtes dans des classes d'aide séparées)
Skeets
15

Vous devez d'abord activer la journalisation des requêtes

DB::enableQueryLog();

Ensuite, vous pouvez obtenir des journaux de requêtes simplement:

dd(DB::getQueryLog());

Il serait préférable d'activer la journalisation des requêtes avant le démarrage de l'application, ce que vous pouvez faire dans un BeforeMiddleware, puis récupérer les requêtes exécutées dans AfterMiddleware.

Vineet Garg
la source
14

Mettez ceci sur le fichier routes.php:

\Event::listen('Illuminate\Database\Events\QueryExecuted', function ($query) {
    echo'<pre>';
    var_dump($query->sql);
    var_dump($query->bindings);
    var_dump($query->time);
    echo'</pre>';
});

Soumis par msurguy, code source dans cette page . Vous trouverez ce code de correctif pour laravel 5.2 dans les commentaires.

Rubén Ruíz
la source
Un peu sale, mais +1 pour les $ query-> bindings et $ query-> time hints
Paolo Stefan
Soigné! L'utilisation de ceci montre les résultats dans la vue, là où la requête se produit!
Charles Wood
11

Apparemment avec Laravel 5.2, la fermeture DB::listenne reçoit qu'un seul paramètre.

Donc, si vous souhaitez utiliser DB::listenLaravel 5.2, vous devez faire quelque chose comme:

DB::listen(
    function ($sql) {
        // $sql is an object with the properties:
        //  sql: The query
        //  bindings: the sql query variables
        //  time: The execution time for the query
        //  connectionName: The name of the connection

        // To save the executed queries to file:
        // Process the sql and the bindings:
        foreach ($sql->bindings as $i => $binding) {
            if ($binding instanceof \DateTime) {
                $sql->bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
            } else {
                if (is_string($binding)) {
                    $sql->bindings[$i] = "'$binding'";
                }
            }
        }

        // Insert bindings into query
        $query = str_replace(array('%', '?'), array('%%', '%s'), $sql->sql);

        $query = vsprintf($query, $sql->bindings);

        // Save the query to file
        $logFile = fopen(
            storage_path('logs' . DIRECTORY_SEPARATOR . date('Y-m-d') . '_query.log'),
            'a+'
        );
        fwrite($logFile, date('Y-m-d H:i:s') . ': ' . $query . PHP_EOL);
        fclose($logFile);
    }
);
Luís Cruz
la source
Pour les Laravel plus anciens, j'ai ajouté ma solution à stackoverflow.com/a/44920198/3823826
Csongor Halmai
8

Pour laravel 5.8, ajoutez simplement dd ou dump .

Ex:

DB::table('users')->where('votes', '>', 100)->dd();

ou

DB::table('users')->where('votes', '>', 100)->dump();

référence: https://laravel.com/docs/5.8/queries#debugging

GN
la source
5

Utilisez toSql()plutôt que get()comme ça:

$users = User::orderBy('name', 'asc')->toSql();
echo $users;
// Outputs the string:
'select * from `users` order by `name` asc'
doncadavona
la source
2

(Laravel 5.2) Je trouve que le moyen le plus simple est simplement d'ajouter une ligne de code pour surveiller les requêtes SQL:

\DB::listen(function($sql) {var_dump($sql); });
ChrisH
la source
1

En continuant de Apparemment avec Laravel 5.2, la fermeture dans DB :: listen ne reçoit qu'un seul paramètre ... réponse ci-dessus: vous pouvez mettre ce code dans le script Middleware et l'utiliser dans les routes.

Aditionellement:

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

$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);
Saint Père
la source
quelle partie doit être placée dans le middleware? qui dans les itinéraires?
user1016265
1

Ce code est pour:

  • Laravel 5.2
  • Connectez les instructions dans la base de données mysql

Voici le code, basé sur la réponse de @milz:

    DB::listen(function($sql) {
        $LOG_TABLE_NAME = 'log';
        foreach ($sql->bindings as $i => $binding) {
            if ($binding instanceof \DateTime) {
                $sql->bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
            } else {
                if (is_string($binding)) {
                    $sql->bindings[$i] = "'$binding'";
                }
            }
        }
        // Insert bindings into query
        $query = str_replace(array('%', '?'), array('%%', '%s'), $sql->sql);
        $query = vsprintf($query, $sql->bindings);
        if(stripos($query, 'insert into `'.$LOG_TABLE_NAME.'`')===false){
            $toLog = new LogModel();
            $toLog->uId = 100;
            $toLog->sql = $query;
            $toLog->save();
        }
    });

Le noyau est la if(stripos...ligne, qui empêche la récursivité de l'insertion de l' insert into loginstruction sql dans la base de données.

ch271828n
la source
0

Je pense que la réponse se trouve dans cet article: https://arjunphp.com/laravel-5-5-log-eloquent-queries/

est rapide et simple à réaliser la journalisation des requêtes.

Il suffit d'ajouter à AppServiceProviderla bootméthode un rappel pour écouter les requêtes DB:

namespace App\Providers;

use DB;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        DB::listen(function($query) {
            logger()->info($query->sql . print_r($query->bindings, true));
        });
    }
}
Javier Núñez
la source
0

Supposons que vous souhaitiez imprimer la requête SQL des instructions suivantes.

$user = User::find(5);

Il vous suffit de procéder comme suit:

DB::enableQueryLog();//enable query logging

$user = User::find(5);

print_r(DB::getQueryLog());//print sql query

Cela imprimera la dernière requête exécutée dans Laravel.

Gufran Hasan
la source
-3

Pour laravel 5 et les versions ultérieures en utilisant uniquement DB :: getQueryLog (), cela ne fonctionnera pas. Par défaut, la valeur de

 protected $loggingQueries = false;

changez-le en

protected $loggingQueries = true; 

dans le fichier ci-dessous pour la requête de journalisation.

/vendor/laravel/framework/src/illuminate/Database/Connection.php 

Et puis nous pouvons utiliser l' DB::getQueryLog()endroit où vous souhaitez imprimer la requête.

Rupali Pemare
la source
1
C'est une mauvaise idée d'éditer des vendorfichiers. Ils doivent être conservés d'origine.
shukshin.ivan
@ shukshin.ivan Oui, il ne faut pas éditer les fichiers du fournisseur mais pour obtenir la requête exacte que nous avons édité ce code pour le moment, nous pouvons le modifier.
Rupali Pemare