Làm thế nào để có được truy vấn được thực hiện trong Laravel 5? DB :: getQueryLog () Trả về mảng trống


171

Tôi đang cố gắng xem nhật ký cho một truy vấn, nhưng DB::getQueryLog()chỉ trả về một mảng trống:

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

Kết quả

Array
(
)

Làm thế nào tôi có thể xem nhật ký cho truy vấn này?


Laravel Debugbar là một công cụ tuyệt vời để ghi lại các truy vấn. Nó cũng có nhiều tính năng tuyệt vời khác.
totymedli

Câu trả lời:


256

Theo mặc định, nhật ký truy vấn bị vô hiệu hóa trong Laravel 5: https://github.com/laravel/framework/commit/e0abfe5c49d225567cb4dfd56df9ef05cc297448

Bạn sẽ cần phải kích hoạt nhật ký truy vấn bằng cách gọi:

DB::enableQueryLog();

hoặc đăng ký một người nghe sự kiện:

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

Một số lời khuyên

1. Nhiều kết nối DB

Nếu bạn có nhiều kết nối DB, bạn phải chỉ định kết nối nào sẽ đăng nhập

Để bật nhật ký truy vấn cho my_connection:

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

Để có được nhật ký truy vấn cho my_connection:

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

2. Nơi để kích hoạt nhật ký truy vấn?

Đối với vòng đời yêu cầu HTTP, bạn có thể kích hoạt nhật ký truy vấn theo handlephương thức của một số BeforeAnyDbQueryMiddleware phần mềm trung gian và sau đó truy xuất các truy vấn đã thực hiện trong terminatephương thức của cùng một phần mềm trung gian.

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

Chuỗi của phần mềm trung gian sẽ không chạy cho các lệnh thủ công, vì vậy để thực thi CLI, bạn có thể bật nhật ký truy vấn trong trình artisan.startnghe sự kiện.

Ví dụ, bạn có thể đặt nó trong bootstrap/app.phptập tin

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

3. Bộ nhớ

Laravel giữ tất cả các truy vấn trong bộ nhớ. Vì vậy, trong một số trường hợp, chẳng hạn như khi chèn một số lượng lớn hàng hoặc có một công việc chạy dài với nhiều truy vấn, điều này có thể khiến ứng dụng sử dụng bộ nhớ dư thừa.

Trong hầu hết các trường hợp, bạn sẽ chỉ cần nhật ký truy vấn để gỡ lỗi và nếu đó là trường hợp tôi khuyên bạn chỉ nên kích hoạt nó để phát triển.

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

Người giới thiệu


6
Nếu hệ thống của bạn sử dụng nhiều kết nối db, bạn phải chỉ định nó, nếu không, nó có thể trả về mảng trống:\DB::connection('myconnection')->enableQueryLog(); print_r(\DB::connection('myconnection')->getQueryLog());
Diana R.

Gửi bình luận của bạn như câu trả lời của bạn @DianaR.
Narendrasingh Sisodia


Làm cách nào để kích hoạt nó để đăng nhập Eloquent "NameContoder :: create ();" tuyên bố?
Rubén Ruíz

2
Lưu ý rằng trong Laravel 5.4, DB::listenchức năng gọi lại có chữ ký khác. Nó giống như thế này: DB::listen(function($query) { $sql = $query->sql; $bindings = $query->bindings; $time = $query->time; ... });
racl101

45

Nếu tất cả những gì bạn thực sự quan tâm là truy vấn thực tế (lần chạy cuối cùng) cho mục đích gỡ lỗi nhanh:

DB::enableQueryLog();

# your laravel query builder goes here

$laQuery = DB::getQueryLog();

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

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

làm một print_r()trên $laQuery[0]để có được những truy vấn đầy đủ, bao gồm các ràng buộc. ( $lcWhatYouWantbiến ở trên sẽ có các biến được thay thế bằng ??)

Nếu bạn đang sử dụng một cái gì đó không phải là kết nối mysql chính, bạn sẽ cần sử dụng những thứ này thay thế:

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

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

(với tên kết nối của bạn là "mysql2")


1
mã này đi đâu mặc dù? (5.4) Tôi đã thử bộ điều khiển, mô hình và xem xét phần mềm trung gian, không biết phải thực thi nó ở đâu trước khi tôi gặp lỗi db.
blamb

Nếu bạn gặp lỗi khi chạy truy vấn đang dừng thực thi, lỗi sẽ cho bạn biết vấn đề là gì. Nếu bạn có lỗi tắt, bạn có thể kiểm tra nhật ký lỗi trong / lưu trữ / log / laravel hoặc một cái gì đó tương tự. . Không chắc chắn những gì bạn đang cố gắng để làm, nhưng bộ điều khiển nghe có vẻ đúng nhất trong các tùy chọn bạn đã đề cập. (Tôi thường chạy các truy vấn trong các lớp trợ giúp riêng biệt)
Skeets

14

Đặt cái này vào tập tin records.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>';
});

Gửi bởi msurguy, mã nguồn trong trang này . Bạn sẽ tìm thấy mã sửa lỗi này cho laravel 5.2 trong các bình luận.


Hơi bẩn, nhưng +1 cho $ query-> ràng buộc và $ query-> gợi ý về thời gian
Paolo Stefan

Khéo léo! Sử dụng điều này cho thấy kết quả trong chế độ xem, ngay tại nơi truy vấn đang xảy ra!
Charles Wood

14

Trước tiên bạn cần bật ghi nhật ký truy vấn

DB::enableQueryLog();

Sau đó, bạn có thể nhận được các bản ghi truy vấn bằng cách đơn giản:

dd(DB::getQueryLog());

Sẽ tốt hơn nếu bạn kích hoạt ghi nhật ký truy vấn trước khi ứng dụng bắt đầu, điều bạn có thể làm trong BeforeMiddleware và sau đó truy xuất các truy vấn đã thực hiện trong AfterMiddleware.


11

Rõ ràng với Laravel 5.2, việc đóng DB::listenchỉ nhận được một tham số duy nhất.

Vì vậy, nếu bạn muốn sử dụng DB::listentrong Laravel 5.2, bạn nên làm một cái gì đó như:

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

Đối với Laravel cũ hơn, tôi đã thêm giải pháp của mình vào stackoverflow.com/a/44920198/3823826
Csongor Halmai


5

Sử dụng toSql()thay vì get()như vậy:

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

2

(Laravel 5.2) Tôi thấy cách đơn giản nhất là chỉ cần thêm một dòng mã để theo dõi các truy vấn sql:

\DB::listen(function($sql) {var_dump($sql); });

1

Tiếp tục với Rõ ràng với Laravel 5.2, việc đóng trong DB :: nghe chỉ nhận được một tham số duy nhất ... phản hồi ở trên: bạn có thể đặt mã này vào tập lệnh Middleware và sử dụng nó trong các tuyến.

Ngoài ra:

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

phần nào nên được đặt vào phần mềm trung gian? Mà trong các tuyến đường?
user1016265

1

Mã này là dành cho:

  • Ấu trùng 5.2
  • Đăng nhập các báo cáo vào cơ sở dữ liệu mysql

Đây là đoạn mã dựa trên câu trả lời của @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();
        }
    });

Cốt lõi là if(stripos...dòng, ngăn chặn sự đệ quy của việc chèn insert into logcâu lệnh sql vào cơ sở dữ liệu.


0

Tôi nghĩ rằng câu trả lời nằm trong bài viết này: https://arjunphp.com/laravel-5-5-log-eloquent-queries/

là nhanh chóng và đơn giản để đạt được đăng nhập truy vấn.

Bạn chỉ cần thêm AppServiceProvidervào bootphương thức một cuộc gọi lại để nghe các truy vấn 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));
        });
    }
}

0

Giả sử bạn muốn in truy vấn SQL của các câu lệnh sau.

$user = User::find(5);

Bạn chỉ cần làm như sau:

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

$user = User::find(5);

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

Điều này sẽ in truy vấn được thực hiện cuối cùng trong Laravel.


-3

Đối với laravel 5 trở đi chỉ sử dụng DB :: getQueryLog (), sẽ không làm được. Theo mặc định trong giá trị này của

 protected $loggingQueries = false;

thay đổi nó thành

protected $loggingQueries = true; 

trong tập tin dưới đây để đăng nhập truy vấn.

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

Và sau đó chúng ta có thể sử dụng DB::getQueryLog()nơi bạn muốn in truy vấn.


1
Đó là một ý tưởng tồi, để chỉnh sửa vendorcác tập tin. Chúng phải được giữ nguyên bản.
shukshin.ivan

@ shukshin.ivan Có một người không được chỉnh sửa các tập tin của nhà cung cấp nhưng để có được truy vấn chính xác, chúng tôi đã chỉnh sửa mã này trong thời gian sau đó chúng tôi có thể thay đổi lại.
Rupali Pemare
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.