วิธีรับแบบสอบถามที่ดำเนินการใน Laravel 5 DB :: getQueryLog () การส่งคืนอาเรย์ที่ว่างเปล่า


172

ฉันพยายามที่จะดูบันทึกการสืบค้น แต่DB::getQueryLog()เพิ่งกลับอาร์เรย์ที่ว่างเปล่า:

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

ผลลัพธ์

Array
(
)

ฉันจะดูบันทึกการสืบค้นนี้ได้อย่างไร


Laravel Debugbarเป็นเครื่องมือที่ยอดเยี่ยมในการบันทึกการสืบค้น นอกจากนี้ยังมีคุณสมบัติที่ยอดเยี่ยมอื่น ๆ อีกมากมาย
totymedli

คำตอบ:


256

โดยค่าเริ่มต้นบันทึกการสืบค้นจะถูกปิดใช้งานใน Laravel 5: https://github.com/laravel/framework/commit/e0abfe5c49d225567cb4dfd56df9ef05cc297448

คุณจะต้องเปิดใช้งานบันทึกแบบสอบถามโดยโทร:

DB::enableQueryLog();

หรือลงทะเบียนฟังเหตุการณ์:

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

เคล็ดลับบางประการ

1. การเชื่อมต่อฐานข้อมูลหลายรายการ

หากคุณมีการเชื่อมต่อฐานข้อมูลมากกว่าหนึ่งรายการคุณต้องระบุการเชื่อมต่อที่จะเข้าสู่ระบบ

วิธีเปิดใช้งานบันทึกคิวรีสำหรับmy_connection:

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

วิธีรับบันทึกคิวรีสำหรับmy_connection:

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

2. จะเปิดใช้งานบันทึกการสืบค้นได้ที่ไหน

สำหรับรอบระยะเวลาการร้องขอ HTTP คุณสามารถเปิดใช้งานการบันทึกแบบสอบถามในhandleวิธีการของBeforeAnyDbQueryMiddleware มิดเดิลแวร์บางส่วนจากนั้นดึงแบบสอบถามที่ดำเนินการแล้วในterminateวิธีการมิดเดิลแวร์เดียวกัน

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

มิดเดิลแวร์ของมิดเดิลแวร์จะไม่รันสำหรับคำสั่ง artisan ดังนั้นสำหรับการประมวลผล CLI คุณสามารถเปิดใช้งานบันทึกแบบสอบถามในตัวartisan.startฟังเหตุการณ์

ตัวอย่างเช่นคุณสามารถวางไว้ในbootstrap/app.phpไฟล์

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

3. หน่วยความจำ

Laravel เก็บข้อความค้นหาทั้งหมดในหน่วยความจำ ดังนั้นในบางกรณีเช่นเมื่อแทรกแถวจำนวนมากหรือมีงานที่ใช้เวลานานซึ่งมีคิวรีจำนวนมากสิ่งนี้อาจทำให้แอปพลิเคชันใช้หน่วยความจำส่วนเกิน

ในกรณีส่วนใหญ่คุณจะต้องใช้บันทึกการสืบค้นสำหรับการดีบักเท่านั้นและหากเป็นกรณีนี้ฉันขอแนะนำให้คุณเปิดใช้เพื่อการพัฒนาเท่านั้น

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

อ้างอิง


6
หากระบบของคุณใช้การเชื่อมต่อมากกว่าหนึ่งฐานข้อมูลคุณต้องระบุมิฉะนั้นอาจส่งคืนอาเรย์ที่ว่างเปล่า:\DB::connection('myconnection')->enableQueryLog(); print_r(\DB::connection('myconnection')->getQueryLog());
Diana R.

โพสต์ความคิดเห็นของคุณเป็นคำตอบของคุณ @DianaR
Narendrasingh Sisodia

1
สำหรับ Laravel 5.2 โปรดดู: laravel.com/docs/5.2/database#listening-for-query-events
Dmitri Chebotarev

วิธีการเปิดใช้งานเพื่อเข้าสู่ระบบ Eloquent "NameController :: create ();" คำให้การ?
RubénRuíz

2
โปรดทราบว่าใน Laravel 5.4 DB::listenฟังก์ชั่นการโทรกลับมีลายเซ็นที่แตกต่างกัน มันเป็นเช่นนี้มากขึ้น: DB::listen(function($query) { $sql = $query->sql; $bindings = $query->bindings; $time = $query->time; ... });
racl101

45

หากสิ่งที่คุณสนใจจริงๆคือแบบสอบถามจริง (การเรียกใช้ครั้งสุดท้าย) เพื่อการดีบักอย่างรวดเร็ว:

DB::enableQueryLog();

# your laravel query builder goes here

$laQuery = DB::getQueryLog();

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

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

ทำprint_r()เกี่ยวกับการ$laQuery[0]ที่จะได้รับการสอบถามเต็มรูปแบบรวมทั้งการผูก ( $lcWhatYouWantตัวแปรด้านบนจะมีตัวแปรที่ถูกแทนที่ด้วย??)

หากคุณกำลังใช้สิ่งอื่นที่ไม่ใช่การเชื่อมต่อ mysql หลักคุณจะต้องใช้สิ่งเหล่านี้แทน:

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

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

(ด้วยชื่อการเชื่อมต่อของคุณที่ "mysql2")


1
รหัสนี้ไปที่ไหน (5.4) ฉันลองใช้คอนโทรลเลอร์รุ่นและดูในมิดเดิลแวร์ไม่แน่ใจว่าจะใช้งานที่ไหนก่อนที่ฉันจะได้รับข้อผิดพลาด db
blamb

หากคุณได้รับข้อผิดพลาดเมื่อเรียกใช้คิวรีที่หยุดการประมวลผลข้อผิดพลาดควรบอกคุณว่าปัญหาคืออะไร หากคุณมีข้อผิดพลาดปิดคุณสามารถตรวจสอบบันทึกข้อผิดพลาดใน / storage / log / laravel หรืออะไรทำนองนั้น (ฉันไม่ได้อยู่ที่คอมพิวเตอร์ของฉันในขณะนี้) หากคุณกำลังบอกว่าคุณได้รับข้อผิดพลาดในการเรียกใช้รหัสที่ฉันแนะนำในคำตอบของฉันตรวจสอบให้แน่ใจว่าคุณได้รวมซุ้มฐานข้อมูล DB ทุกที่ที่คุณใช้รหัส ไม่แน่ใจว่าคุณกำลังพยายามทำอะไร แต่คอนโทรลเลอร์จะฟังดูเหมือนตัวเลือกที่ถูกต้องที่สุด (ฉันมักจะเรียกใช้แบบสอบถามในชั้นเรียนแยกช่วยเหลือ)
Skeets

14

วางสิ่งนี้ไว้บนไฟล์ route.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>';
});

ส่งโดย msurguy ซอร์สโค้ดในหน้านี้ คุณจะพบรหัสแก้ไขนี้สำหรับ laravel 5.2 ในความคิดเห็น


ค่อนข้างสกปรก แต่ +1 สำหรับ $ query-> การเชื่อมโยงและ $ query-> คำแนะนำเวลา
Paolo Stefan

เรียบร้อย! การใช้สิ่งนี้จะแสดงผลลัพธ์ในมุมมองทันทีที่เกิดคิวรี!
Charles Wood

14

คุณต้องเปิดใช้งานการบันทึกคิวรีก่อน

DB::enableQueryLog();

จากนั้นคุณสามารถรับบันทึกคิวรีได้ง่ายๆเพียง:

dd(DB::getQueryLog());

จะเป็นการดีกว่าถ้าคุณเปิดใช้งานการบันทึกแบบสอบถามก่อนเริ่มต้นแอปพลิเคชันซึ่งคุณสามารถทำได้ใน BeforeMiddleware แล้วดึงการสืบค้นที่ดำเนินการใน AfterMiddleware


11

เห็นได้ชัดกับ Laravel 5.2 การปิดในDB::listenได้รับพารามิเตอร์เดียวเท่านั้น

ดังนั้นหากคุณต้องการใช้DB::listenใน Laravel 5.2 คุณควรทำดังนี้:

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

สำหรับ Laravel รุ่นเก่าฉันได้เพิ่มโซลูชันของฉันไปที่stackoverflow.com/a/44920198/3823826
Csongor Halmai


5

ใช้toSql()แทนget()อย่างเช่น:

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

2

(Laravel 5.2) ฉันพบวิธีที่ง่ายที่สุดคือเพียงเพิ่มโค้ดหนึ่งบรรทัดเพื่อตรวจสอบเคียวรี sql:

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

1

ในการดำเนินการตามApparently กับ Laravel 5.2 การปิดใน DB :: Listen จะได้รับพารามิเตอร์เดียว ...การตอบสนองด้านบน: คุณสามารถใส่รหัสนี้ในสคริปต์ Middleware และใช้ในเส้นทาง

นอกจากนี้:

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

ส่วนไหนที่ควรวางไว้ในมิดเดิลแวร์ เส้นทางไหน
user1016265

1

รหัสนี้สำหรับ:

  • Laravel 5.2
  • บันทึกคำสั่งลงในฐานข้อมูล mysql

นี่คือรหัสซึ่งขึ้นอยู่กับคำตอบของ @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();
        }
    });

หลักคือif(stripos...สายซึ่งป้องกันการเรียกซ้ำinsert into logคำสั่ง sql ลงในฐานข้อมูล


0

ฉันคิดว่าคำตอบที่อยู่ในบทความนี้: https://arjunphp.com/laravel-5-5-log-eloquent-queries/

รวดเร็วและง่ายในการบันทึกการสืบค้น

คุณเพียงแค่ต้องเพิ่มAppServiceProviderในbootวิธีการโทรกลับเพื่อฟังแบบสอบถาม 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

สมมติว่าคุณต้องการพิมพ์แบบสอบถาม SQL ของคำสั่งต่อไปนี้

$user = User::find(5);

คุณเพียงแค่ต้องทำดังนี้:

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

$user = User::find(5);

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

นี่จะพิมพ์คิวรี่ที่ถูกเรียกใช้ล่าสุดใน Laravel


-3

สำหรับ laravel 5 ขึ้นไปโดยใช้เฉพาะ DB :: getQueryLog () จะไม่ทำ โดยค่าเริ่มต้นในนี้ค่าของ

 protected $loggingQueries = false;

เปลี่ยนเป็น

protected $loggingQueries = true; 

ในไฟล์ด้านล่างสำหรับบันทึกการสืบค้น

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

จากนั้นเราสามารถใช้DB::getQueryLog()ตำแหน่งที่คุณต้องการพิมพ์แบบสอบถาม


1
เป็นความคิดที่ดีที่จะแก้ไขvendorไฟล์ พวกเขาจะต้องเก็บไว้เป็นต้นฉบับ
shukshin.ivan

@ shukshin.ivan ใช่ต้องไม่แก้ไขไฟล์ผู้จำหน่าย แต่เพื่อให้ได้คำค้นหาที่ถูกต้องเราได้แก้ไขรหัสนี้ในขณะนั้นเราสามารถเปลี่ยนกลับได้
Rupali Pemare
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.