Laravel 编码技巧 - 日志与调式

作者: 温新

图书: 【Laravel 编码技巧】

阅读: 153

时间: 2024-03-01 15:19:46

记录日志参数

你可以使用 Log::info(),或使用更短的 info() 额外参数信息,来了解更多发生的事情

Log::info('User failed to login.', ['id' => $user->id]);

Laravel长时间运行日志

//  App\Providers\AppServiceProvider.php

public function boot(): void
{
    DB::enableQueryLog();

    DB::whenQueryingForLongerThan(1000, function ($connection, $query) {
        Log::info('time: ' . $query->time . ' Slow SQL:' .  $query->sql);
    });
}

基准类

在 Laravel 9.32 中,我们引入了 Benchmark 类,它可以测量任何任务的执行时间。

这是一个非常有用的辅助类:

use Illuminate\Support\Benchmark;

class OrderController
{
    public function index()
    {
        return Benchmark::measure(fn () => Order::all());
    }
}

更方便的 DD

与其使用 dd($result),您可以将 ->dd() 直接放在您的 Eloquent 查询或任何集合的末尾。

// 替代方式
$users = User::where('name', 'Taylor')->get();
dd($users);

// 使用 ->dd()
$users = User::where('name', 'Taylor')->get()->dd();

带上下文的日志

在 Laravel 8.49 中新增了 Log::withContext() 方法,它可以帮助您区分不同请求之间的日志消息。

如果您创建一个中间件并设置了这个上下文,所有的日志消息都将包含该上下文,从而使您更容易进行搜索。

use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

public function handle(Request $request, Closure $next)
{
    $requestId = (string) Str::uuid();

    Log::withContext(['request-id' => $requestId]);

    $response = $next($request);

    $response->header('request-id', $requestId);

    return $response;
}

在上述示例中,Log::withContext(['request-id' => $requestId]) 用于设置一个请求标识的上下文,这样所有的日志消息都将包含这个上下文。这对于在多个请求之间轻松区分日志消息非常有用。

快速输出 Eloquent 查询的 SQL 形式

如果你想快速输出一个 Eloquent 查询的 SQL 形式,可以使用 toSql() 方法:

$invoices = Invoice::where('client', 'James pay')->toSql();

dd($invoices);
// select * from `invoices` where `client` = ?

在开发过程中记录所有数据库查询

如果您想在开发过程中记录所有的数据库查询,可以将以下代码段添加到您的 AppServiceProvider 中:

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\App;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;

public function boot()
{
    if (App::environment('local')) {
        DB::listen(function ($query) {
            logger(Str::replaceArray('?', $query->bindings, $query->sql));
        });
    }
}

在一次请求中发现所有触发的事件

如果您想要实现对特定事件的新监听器,但不知道其名称,可以记录请求期间触发的所有事件。

您可以在 app/Providers/EventServiceProvider.php 文件的 boot() 方法中使用 \Illuminate\Support\Facades\Event::listen() 方法来捕获所有触发的事件。

重要提示:如果在此事件监听器内使用 Log 门面,则需要排除名为 Illuminate\Log\Events\MessageLogged 的事件,以避免无限循环。 (例如:if ($event == 'Illuminate\\Log\\Events\\MessageLogged') return;

// 在 EventServiceProvider 类中包含 Event...
use Illuminate\Support\Facades\Event;

// 在您的 EventServiceProvider 类的 boot 方法中...
public function boot()
{
    parent::boot();

    Event::listen('*', function ($event, array $data) {
        // 记录事件类
        error_log($event);

        // 记录委托给监听器参数的事件数据
        error_log(json_encode($data, JSON_PRETTY_PRINT));
    });
}

在上述示例中,Event::listen('*') 方法用于注册一个通用监听器,它将捕获所有触发的事件并记录事件类和数据。这对于在开发过程中了解事件的名称和结构非常有用。请注意,这样做可能会产生大量的日志输出,因此在生产环境中慎用。

请登录后再评论