Laravel 编码技巧 - 日志与调式
记录日志参数
你可以使用 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('*')
方法用于注册一个通用监听器,它将捕获所有触发的事件并记录事件类和数据。这对于在开发过程中了解事件的名称和结构非常有用。请注意,这样做可能会产生大量的日志输出,因此在生产环境中慎用。