Laravel là một Framework PHP mạnh mẽ và linh hoạt, giúp cho việc phát triển ứng dụng trở nên đơn giản và dễ dàng hơn.

Một trong những tính năng hữu ích của Laravel là khả năng ghi nhật ký truy vấn SQL. Ghi nhật ký truy vấn SQL là một cách tuyệt vời để theo dõi hiệu suất ứng dụng của bạn và xác định các vấn đề tiềm ẩn.

Trong hướng dẫn này, chúng ta sẽ cùng nhau khám phá cách ghi nhật ký truy vấn cơ sở dữ liệu trong Laravel. Để quản lý việc ghi nhật kí truy vấn SQL một cách hiệu quả, chúng ta sẽ sử dụng ServiceProvider.

Để tạo một ServiceProvider mới để quản lý truy vấn SQL, chúng ta sử dụng command sau:

php artisan make:provider DatabaseQueryServiceProvider

Sau khi tạo ServiceProvider, chúng ta cần đăng ký nó trong config/app.php. Để làm điều này, chúng ta thêm dòng sau vào mảng providers:

'providers' => [
    ...
    App\Providers\DatabaseQueryServiceProvider::class,
],

Tiếp theo, bạn hãy chỉnh sửa mã nguồn DatabaseQueryServiceProvider.php như sau:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Events\TransactionBeginning;
use Illuminate\Database\Events\TransactionCommitted;
use Illuminate\Database\Events\TransactionRolledBack;

class DatabaseQueryServiceProvider extends ServiceProvider
{
    // Define the log channel for database queries
    protected $channel = 'sql';

    /**
     * Register services.
     */
    public function register(): void
    {
        // Store the channel in a variable for use in closures
        $channel = $this->channel;

        // Check if the log channel is enabled in the configuration
        if (!config("logging.channels.{$channel}.enable")) {
            return;
        }

        // Listen to database queries and log them
        DB::listen(static function ($query) use ($channel) {
            $sql            = vsprintf(str_replace('?', "'%s'", $query->sql), $query->bindings);
            $execution_time = $query->time;
            // Determine log level based on execution time
            $log_level      = $execution_time > config("logging.channels.{$channel}.slow_query_time") ? 'warning' : 'debug';
            // Log the query with execution time and SQL statement
            Log::channel($channel)->$log_level(sprintf('%.2f ms, SQL: %s;', $execution_time, $sql));
        });

        // Listen to the beginning of a database transaction and log it
        Event::listen(static function (TransactionBeginning $event) use ($channel) {
            Log::channel($channel)->debug('BEGIN TRANSACTION');
        });

        // Listen to the successful commit of a database transaction and log it
        Event::listen(static function (TransactionCommitted $event) use ($channel) {
            Log::channel($channel)->debug('COMMIT');
        });

        // Listen to the rollback of a database transaction and log it
        Event::listen(static function (TransactionRolledBack $event) use ($channel) {
            Log::channel($channel)->debug('ROLLBACK');
        });
    }
}

Tiếp tục, chúng ta sẽ tạo một channel logging dành riêng cho việc ghi lại nhật kí truy vấn SQL trong hệ thống, bạn hãy thêm mã nguồn sau vào config/logging.php:

'channels' => [
    ...
    'sql' => [
        'driver' => 'daily',
        'path' => storage_path('logs/query.log'),
        'level' => env('LOG_LEVEL', 'debug'),
        'enable' => env('LOG_SQL_ENABLE', false),
        'slow_query_time' => env('LOG_SQL_SLOW_QUERY_TIME', 2000),
    ],
],

Để sử dụng tính năng ghi nhật kí truy vấn SQL, bạn cần cấu hình các giá trị bên dưới vào .env:

LOG_SQL_ENABLE=true
LOG_SQL_SLOW_QUERY_TIME=1000

Bây giờ, để xem mọi thứ có hoạt động như mong đợi không, hãy tạo UserController.php với nội dung sau:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\DB;

class UserController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        # Rollback Example
        try {
            // Begin a database transaction
            DB::beginTransaction();
            // Create a new User with provided data
            User::create([
                'name' => 'ManhDanBlogs (Beater)',
                'email' => '[email protected]',
                'email_verified_at' => now(),
                'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
                'remember_token' => Str::random(10),
            ]);
            // Simulate an error (division by zero) to trigger rollback
            $bug = 1 / 0;
            // Commit the transaction if no exception is thrown
            DB::commit();
        } catch (Throwable $th) {
            // Log and report any exceptions
            report($th);
            // Rollback the transaction in case of an exception
            DB::rollBack();
        }

        # Not Rollback Example
        try {
            // Begin a database transaction
            DB::beginTransaction();
            // Create a new User with provided data
            $user = User::create([
                'name' => 'ManhDanBlogs (Beater)',
                'email' => '[email protected]',
                'email_verified_at' => now(),
                'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
                'remember_token' => Str::random(10),
            ]);
            // Commit the transaction if no exception is thrown
            DB::commit();
        } catch (Throwable $th) {
            // Log and report any exceptions
            report($th);
            // Rollback the transaction in case of an exception
            DB::rollBack();
        }
        // Attempt to retrieve the User with the provided ID (outside of the transaction)
        User::find($user->id);
    }
    .....
}

Sau khi chạy mã nguồn UserController.php, bạn sẽ thấy chi tiết tất cả truy vấn SQL được thực hiện, bao gồm cả truy vấn thành công và thất bại, với thời gian thực thi để phân tích hiệu suất.

-rw-r--r-- 1 root root 2,3K Thg 12  1 08:11 query-2023-12-04.log
tail -fn 1000 query-2023-12-04.log 
[2023-12-04 14:17:02] local.DEBUG: BEGIN TRANSACTION  
[2023-12-04 14:17:02] local.WARNING: 1.95 ms, SQL: insert into `users` (`name`, `email`, `password`, `updated_at`, `created_at`) values ('ManhDanBlogs (Beater)', '[email protected]', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', '2023-12-04 14:17:02', '2023-12-04 14:17:02');  
[2023-12-04 14:17:02] local.DEBUG: ROLLBACK  
[2023-12-04 14:17:02] local.DEBUG: BEGIN TRANSACTION  
[2023-12-04 14:17:02] local.DEBUG: 0.20 ms, SQL: insert into `users` (`name`, `email`, `password`, `updated_at`, `created_at`) values ('ManhDanBlogs (Beater)', '[email protected]', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', '2023-12-04 14:17:02', '2023-12-04 14:17:02');  
[2023-12-04 14:17:02] local.DEBUG: COMMIT  
[2023-12-04 14:17:02] local.DEBUG: 0.46 ms, SQL: select * from `users` where `users`.`id` = '1007' limit 1; 

Bạn hãy tận hưởng cảm giác an tâm và chủ động với tính năng ghi nhật kí truy vấn SQL mạnh mẽ này. Giờ đây, tối ưu hóa truy vấn và sửa lỗi trở nên đơn giản hơn bao giờ hết! 🚀🚀🚀🚀🚀

CÓ THỂ BẠN QUAN TÂM

Laravel UI Custom Email Password Reset Template

Laravel UI Custom Email Password Reset Template

Nếu bạn đang dùng thư viện laravel/ui để làm các chức năng liên quan đến authentication, và trong dự án của bạn, bạn cần thay đổi template email password reset thay vì sử dụng template email password...

Defer in Laravel: Push Tasks to the Background

Defer in Laravel: Push Tasks to the Background

Deferred Functions trong Laravel Các phiên bản Laravel trước version 11, chúng ta thường sử dụng Queued Jobs cho phép thực hiện sắp xếp các tác vụ xử lý background . Nhưng đôi khi có những tác v...

Integrating elFinder Into CKEditor 5 In Laravel

Integrating elFinder Into CKEditor 5 In Laravel

CKEditor 5 CKEditor 5 là một trình soạn thảo văn bản phong phú JavaScript với nhiều tính năng và khả năng tùy chỉnh. CKEditor 5 có kiến trúc MVC hiện đại, mô hình dữ liệu tùy chỉnh và DOM ảo, mang...

Laravel Model

Laravel Model

Model là gì? Trong mô hình MVC, chữ “M” viết tắt là Model, Model dùng để xử lý logic nghiệp vụ trong bất kì ứng dụng dựa trên mô hình MVC. Trong Laravel, Model là lớp đại diện cho cấu trúc logic và...

Csv import with Validation for Laravel

Csv import with Validation for Laravel

Trong một bài viết lúc trước, mình đã chia sẻ đến các bạn cách xây dựng một service import và export CSV sử dụng Facades, nếu có bạn nào không biết hoặc đã quên các bạn có thể tham khảo lại bài viết t...

Laravel Many to Many Polymorphic Relationship

Laravel Many to Many Polymorphic Relationship

Many to many Polymorphic Relationship cũng hơi phức tạp để hiểu. Ví dụ: nếu bạn có bài post, video và tag, bạn cần kết nối với nhau theo yêu cầu là mọi bài đăng đều có nhiều tag và video cũng như vậy....

Google Drive as Filesystem in Laravel

Google Drive as Filesystem in Laravel

Đối với một số dự án, bạn cần phải sử dụng Google Drive (với tài khoản @gmail.com cá nhân hoặc tài khoản G Suite) làm nhà cung cấp bộ nhớ trong các dự án Laravel. Trong bài đăng này, tôi sẽ hướng d...

Laravel User Authentication

Laravel User Authentication

Trong hướng dẫn này, tôi sẽ hướng dẫn bạn xây dựng chức năng đăng nhập trong Laravel. Công bằng mà nói thì bạn có thể sử dụng Laravel UI hoặc JetStream để tự động tạo ra chức năng đăng nhập trong Lara...

Integrating AI Assistant with CKEditor 5 in Laravel using Vite

Integrating AI Assistant with CKEditor 5 in Laravel using Vite

OpenAI OpenAI là một công ty nghiên cứu và triển khai trí tuệ nhân tạo, nổi tiếng với việc phát triển các mô hình AI tiên tiến. Mục tiêu của OpenAI là đảm bảo rằng trí tuệ nhân tạo tổng quát (AGI...

ManhDanBlogs