Laravel Pulse
简介
Laravel Pulse 提供应用性能和使用情况的一览式洞察。借助 Pulse,你可以追踪慢任务、慢端点等瓶颈,找出最活跃的用户等。
若要深入调试单个事件,请参阅 Laravel Telescope。
安装
WARNING
Pulse 的一方可存储实现目前需要 MySQL、MariaDB 或 PostgreSQL 数据库。若使用其他数据库引擎,需要单独的 MySQL、MariaDB 或 PostgreSQL 数据库存储 Pulse 数据。
可通过 Composer 安装 Pulse:
composer require laravel/pulse接下来,使用 vendor:publish Artisan 命令发布 Pulse 配置和迁移文件:
php artisan vendor:publish --provider="Laravel\Pulse\PulseServiceProvider"最后,运行 migrate 命令创建存储 Pulse 数据所需的表:
php artisan migrate运行 Pulse 数据库迁移后,可通过 /pulse 路由访问 Pulse 仪表盘。
INFO
若不想在主数据库中存储 Pulse 数据,可指定专用数据库连接。
配置
Pulse 的许多配置选项可通过环境变量控制。要查看可用选项、注册新 recorder 或配置高级选项,可发布 config/pulse.php 配置文件:
php artisan vendor:publish --tag=pulse-config仪表盘
授权
Pulse 仪表盘可通过 /pulse 路由访问。默认情况下,仅在 local 环境可访问,因此需通过自定义 'viewPulse' 授权 Gate 为生产环境配置授权。可在 app/Providers/AppServiceProvider.php 中完成:
use App\Models\User;
use Illuminate\Support\Facades\Gate;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Gate::define('viewPulse', function (User $user) {
return $user->isAdmin();
});
// ...
}自定义
可通过发布仪表盘视图配置 Pulse 仪表盘卡片和布局。仪表盘视图将发布到 resources/views/vendor/pulse/dashboard.blade.php:
php artisan vendor:publish --tag=pulse-dashboard仪表盘由 Livewire 驱动,无需重新构建 JavaScript 资源即可自定义卡片和布局。
在此文件中,<x-pulse> 组件负责渲染仪表盘并为卡片提供网格布局。若希望仪表盘占满屏幕宽度,可向组件提供 full-width 属性:
<x-pulse full-width>
...
</x-pulse>默认情况下,<x-pulse> 组件创建 12 列网格,但可使用 cols 属性自定义:
<x-pulse cols="16">
...
</x-pulse>每个卡片接受 cols 和 rows 属性以控制空间和位置:
<livewire:pulse.usage cols="4" rows="2" />大多数卡片还接受 expand 属性,以显示完整卡片而非滚动:
<livewire:pulse.slow-queries expand />解析用户
对于显示用户信息的卡片(如 Application Usage 卡片),Pulse 仅记录用户 ID。渲染仪表盘时,Pulse 会从默认 Authenticatable 模型解析 name 和 email 字段,并使用 Gravatar 服务显示头像。
可在 App\Providers\AppServiceProvider 中调用 Pulse::user 方法自定义字段和头像。
user 方法接受闭包,接收要显示的 Authenticatable 模型,并应返回包含 name、extra 和 avatar 信息的数组:
use Laravel\Pulse\Facades\Pulse;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Pulse::user(fn ($user) => [
'name' => $user->name,
'extra' => $user->email,
'avatar' => $user->avatar_url,
]);
// ...
}INFO
可通过实现 Laravel\Pulse\Contracts\ResolvesUsers 契约并在 Laravel 服务容器 中绑定,完全自定义已认证用户的捕获和检索方式。
卡片
服务器
<livewire:pulse.servers /> 卡片显示运行 pulse:check 命令的所有服务器的系统资源使用情况。有关系统资源报告的更多信息,请参阅 servers recorder 文档。
若在基础设施中更换服务器,可能希望在给定时间后停止在 Pulse 仪表盘中显示不活跃的服务器。可使用 ignore-after 属性,接受不活跃服务器应从 Pulse 仪表盘移除的秒数。也可提供相对时间格式字符串,如 1 hour 或 3 days and 1 hour:
<livewire:pulse.servers ignore-after="3 hours" />应用使用情况
<livewire:pulse.usage /> 卡片显示向应用发起请求、分派任务和遇到慢请求的前 10 名用户。
若希望同时在屏幕上查看所有使用指标,可多次包含该卡片并指定 type 属性:
<livewire:pulse.usage type="requests" />
<livewire:pulse.usage type="slow_requests" />
<livewire:pulse.usage type="jobs" />要了解如何自定义 Pulse 检索和显示用户信息,请参阅解析用户文档。
INFO
若应用接收大量请求或分派大量任务,可考虑启用采样。更多信息请参阅 user requests recorder、user jobs recorder 和 slow jobs recorder 文档。
异常
<livewire:pulse.exceptions /> 卡片显示应用中异常的发生频率和最近情况。默认情况下,异常按异常类和发生位置分组。更多信息请参阅 exceptions recorder 文档。
队列
<livewire:pulse.queues /> 卡片显示应用中队列的吞吐量,包括已入队、处理中、已处理、已释放和失败的任务数量。更多信息请参阅 queues recorder 文档。
慢请求
<livewire:pulse.slow-requests /> 卡片显示超过配置阈值(默认 1000ms)的传入请求。更多信息请参阅 slow requests recorder 文档。
慢任务
<livewire:pulse.slow-jobs /> 卡片显示超过配置阈值(默认 1000ms)的队列任务。更多信息请参阅 slow jobs recorder 文档。
慢查询
<livewire:pulse.slow-queries /> 卡片显示超过配置阈值(默认 1000ms)的数据库查询。
默认情况下,慢查询按 SQL 查询(不含绑定)和发生位置分组,但若希望仅按 SQL 查询分组,可选择不捕获位置。
若因极大 SQL 查询的语法高亮导致渲染性能问题,可添加 without-highlighting 属性禁用高亮:
<livewire:pulse.slow-queries without-highlighting />更多信息请参阅 slow queries recorder 文档。
慢出站请求
<livewire:pulse.slow-outgoing-requests /> 卡片显示使用 Laravel HTTP 客户端 发出且超过配置阈值(默认 1000ms)的出站请求。
默认情况下,条目按完整 URL 分组。但可使用正则表达式规范化或分组相似的出站请求。更多信息请参阅 slow outgoing requests recorder 文档。
缓存
<livewire:pulse.cache /> 卡片显示应用的全局和单个键的缓存命中与未命中统计。
默认情况下,条目按键分组。但可使用正则表达式规范化或分组相似的键。更多信息请参阅 cache interactions recorder 文档。
捕获条目
大多数 Pulse recorder 会根据 Laravel 分派的事件自动捕获条目。但 servers recorder 和部分第三方卡片需定期轮询信息。要使用这些卡片,必须在所有应用服务器上运行 pulse:check 守护进程:
php artisan pulse:checkINFO
要在后台永久运行 pulse:check 进程,应使用 Supervisor 等进程监控器确保命令不会停止。
pulse:check 是长时间运行的进程,不重启不会看到代码库变更。部署过程中应调用 pulse:restart 命令优雅重启:
php artisan pulse:restartINFO
Pulse 使用缓存 存储重启信号,使用此功能前请确保已正确配置缓存驱动。
Recorder
Recorder 负责从应用捕获条目并记录到 Pulse 数据库。Recorder 在 Pulse 配置文件 的 recorders 部分注册和配置。
缓存交互
可选择调整采样率和忽略的键模式。
还可配置键分组,将相似键合并为单个条目。例如,可从缓存相同类型信息的键中移除唯一 ID。分组使用正则表达式对键的部分进行「查找和替换」。配置文件中包含示例:
Recorders\CacheInteractions::class => [
// ...
'groups' => [
// '/:\d+/' => ':*',
],
],将使用第一个匹配的模式。若无模式匹配,则按键原样捕获。
异常
Exceptions recorder 捕获应用中可报告异常的信息,用于在 Exceptions 卡片上显示。
可选择调整采样率和忽略的异常模式。还可配置是否捕获异常来源位置。捕获的位置会显示在 Pulse 仪表盘上,有助于追踪异常来源;但若同一异常在多个位置发生,则每个唯一位置都会单独显示。
队列
Queues recorder 捕获应用队列信息,用于在 Queues 卡片上显示。
可选择调整采样率和忽略的任务模式。
慢任务
SlowJobs recorder 捕获应用中慢任务的信息,用于在 Slow Jobs 卡片上显示。
可选择调整慢任务阈值、采样率和忽略的任务模式。
某些任务可能比其他任务耗时更长。此时可配置每个任务的阈值:
Recorders\SlowJobs::class => [
// ...
'threshold' => [
'#^App\\Jobs\\GenerateYearlyReports$#' => 5000,
'default' => env('PULSE_SLOW_JOBS_THRESHOLD', 1000),
],
],若无正则表达式模式匹配任务的类名,则使用 'default' 值。
慢出站请求
SlowOutgoingRequests recorder 捕获使用 Laravel HTTP 客户端 发出且超过配置阈值的出站 HTTP 请求信息,用于在 Slow Outgoing Requests 卡片上显示。
可选择调整慢出站请求阈值、采样率和忽略的 URL 模式。
某些出站请求可能比其他请求耗时更长。此时可配置每个请求的阈值:
Recorders\SlowOutgoingRequests::class => [
// ...
'threshold' => [
'#backup.zip$#' => 5000,
'default' => env('PULSE_SLOW_OUTGOING_REQUESTS_THRESHOLD', 1000),
],
],若无正则表达式模式匹配请求的 URL,则使用 'default' 值。
还可配置 URL 分组,将相似 URL 合并为单个条目。例如,可从 URL 路径中移除唯一 ID,或仅按域名分组。分组使用正则表达式对 URL 的部分进行「查找和替换」。配置文件中包含一些示例:
Recorders\SlowOutgoingRequests::class => [
// ...
'groups' => [
// '#^https://api\.github\.com/repos/.*$#' => 'api.github.com/repos/*',
// '#^https?://([^/]*).*$#' => '\1',
// '#/\d+#' => '/*',
],
],将使用第一个匹配的模式。若无模式匹配,则按 URL 原样捕获。
慢查询
SlowQueries recorder 捕获应用中超过配置阈值的任何数据库查询,用于在 Slow Queries 卡片上显示。
可选择调整慢查询阈值、采样率和忽略的查询模式。还可配置是否捕获查询位置。捕获的位置会显示在 Pulse 仪表盘上,有助于追踪查询来源;但若同一查询在多个位置执行,则每个唯一位置都会单独显示。
某些查询可能比其他查询耗时更长。此时可配置每个查询的阈值:
Recorders\SlowQueries::class => [
// ...
'threshold' => [
'#^insert into `yearly_reports`#' => 5000,
'default' => env('PULSE_SLOW_QUERIES_THRESHOLD', 1000),
],
],若无正则表达式模式匹配查询的 SQL,则使用 'default' 值。
慢请求
Requests recorder 捕获发往应用的请求信息,用于在 Slow Requests 和 Application Usage 卡片上显示。
可选择调整慢路由阈值、采样率和忽略的路径。
某些请求可能比其他请求耗时更长。此时可配置每个请求的阈值:
Recorders\SlowRequests::class => [
// ...
'threshold' => [
'#^/admin/#' => 5000,
'default' => env('PULSE_SLOW_REQUESTS_THRESHOLD', 1000),
],
],若无正则表达式模式匹配请求的 URL,则使用 'default' 值。
服务器
Servers recorder 捕获支撑应用的服务器的 CPU、内存和存储使用情况,用于在 Servers 卡片上显示。此 recorder 需要在要监控的每台服务器上运行 pulse:check 命令。
每台上报服务器必须有唯一名称。默认情况下,Pulse 使用 PHP gethostname 函数返回的值。若要自定义,可设置 PULSE_SERVER_NAME 环境变量:
PULSE_SERVER_NAME=load-balancerPulse 配置文件还允许自定义要监控的目录。
用户任务
UserJobs recorder 捕获应用中分派任务的用户信息,用于在 Application Usage 卡片上显示。
可选择调整采样率和忽略的任务模式。
用户请求
UserRequests recorder 捕获向应用发起请求的用户信息,用于在 Application Usage 卡片上显示。
可选择调整采样率和忽略的 URL 模式。
过滤
如前所述,许多 recorder 可通过配置根据其值(如请求 URL)「忽略」传入条目。但有时根据其他因素(如当前已认证用户)过滤记录也很有用。要过滤这些记录,可向 Pulse 的 filter 方法传递闭包。通常应在 AppServiceProvider 的 boot 方法中调用 filter 方法:
use Illuminate\Support\Facades\Auth;
use Laravel\Pulse\Entry;
use Laravel\Pulse\Facades\Pulse;
use Laravel\Pulse\Value;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Pulse::filter(function (Entry|Value $entry) {
return Auth::user()->isNotAdmin();
});
// ...
}性能
Pulse 设计为可直接接入现有应用,无需额外基础设施。但对于高流量应用,有几种方式可消除 Pulse 对应用性能的影响。
使用不同数据库
对于高流量应用,你可能希望为 Pulse 使用专用数据库连接,以避免影响应用数据库。
通过设置 PULSE_DB_CONNECTION 环境变量,可自定义 Pulse 使用的数据库连接:
PULSE_DB_CONNECTION=pulseRedis 摄取
WARNING
Redis 摄取需要 Redis 6.2 或更高版本,且应用配置的 Redis 客户端驱动为 phpredis 或 predis。
默认情况下,Pulse 在 HTTP 响应发送给客户端或任务处理完成后,直接将条目存储到配置的数据库连接;但也可使用 Pulse 的 Redis 摄取驱动将条目发送到 Redis stream。通过配置 PULSE_INGEST_DRIVER 环境变量启用:
PULSE_INGEST_DRIVER=redisPulse 默认使用默认 Redis 连接,但可通过 PULSE_REDIS_CONNECTION 环境变量自定义:
PULSE_REDIS_CONNECTION=pulse使用 Redis 摄取时,需运行 pulse:work 命令监控 stream 并将条目从 Redis 移入 Pulse 数据库表。
php artisan pulse:workINFO
要在后台永久运行 pulse:work 进程,应使用 Supervisor 等进程监控器确保 Pulse worker 不会停止。
pulse:work 是长时间运行的进程,不重启不会看到代码库变更。部署过程中应调用 pulse:restart 命令优雅重启:
php artisan pulse:restartINFO
Pulse 使用缓存 存储重启信号,使用此功能前请确保已正确配置缓存驱动。
采样
默认情况下,Pulse 会捕获应用中发生的每个相关事件。对于高流量应用,这可能导致仪表盘需要聚合数百万数据库行,尤其是较长时间段。
也可选择在特定 Pulse 数据 recorder 上启用「采样」。例如,在 User Requests recorder 上将采样率设为 0.1 意味着仅记录约 10% 的请求。仪表盘中,值会被放大并以 ~ 为前缀,表示为近似值。
通常,某指标的条目越多,就越可以安全地降低采样率而不牺牲太多准确性。
修剪
Pulse 会在存储条目超出仪表盘窗口后自动修剪。修剪在摄取数据时通过抽奖系统发生,可在 Pulse 配置文件 中自定义。
处理 Pulse 异常
捕获 Pulse 数据时若发生异常(如无法连接存储数据库),Pulse 会静默失败以避免影响应用。
若要自定义这些异常的处理方式,可向 handleExceptionsUsing 方法提供闭包:
use Laravel\Pulse\Facades\Pulse;
use Illuminate\Support\Facades\Log;
Pulse::handleExceptionsUsing(function ($e) {
Log::debug('An exception happened in Pulse', [
'message' => $e->getMessage(),
'stack' => $e->getTraceAsString(),
]);
});自定义卡片
卡片组件
在 Laravel Pulse 中创建自定义卡片,首先需扩展基础 Card Livewire 组件并定义对应视图:
namespace App\Livewire\Pulse;
use Laravel\Pulse\Livewire\Card;
use Livewire\Attributes\Lazy;
#[Lazy]
class TopSellers extends Card
{
public function render()
{
return view('livewire.pulse.top-sellers');
}
}使用 Livewire 的懒加载功能时,Card 组件会自动提供占位符,尊重传递给组件的 cols 和 rows 属性。
编写 Pulse 卡片对应视图时,可利用 Pulse 的 Blade 组件保持一致的观感:
<x-pulse::card :cols="$cols" :rows="$rows" :class="$class" wire:poll.5s="">
<x-pulse::card-header name="Top Sellers">
<x-slot:icon>
...
</x-slot:icon>
</x-pulse::card-header>
<x-pulse::scroll :expand="$expand">
...
</x-pulse::scroll>
</x-pulse::card>$cols、$rows、$class 和 $expand 变量应传递给相应的 Blade 组件,以便从仪表盘视图自定义卡片布局。还可在视图中包含 wire:poll.5s="" 属性使卡片自动更新。
定义 Livewire 组件和模板后,可在仪表盘视图中包含该卡片:
<x-pulse>
...
<livewire:pulse.top-sellers cols="4" />
</x-pulse>INFO
若卡片包含在包中,需使用 Livewire::component 方法向 Livewire 注册组件。
样式
若卡片需要 Pulse 包含的类和组件之外的额外样式,有几种方式为卡片包含自定义 CSS。
Laravel Vite 集成
若自定义卡片位于应用代码库中且使用 Laravel Vite 集成,可更新 vite.config.js 为卡片包含专用 CSS 入口点:
laravel({
input: [
'resources/css/pulse/top-sellers.css',
// ...
],
}),然后可在仪表盘视图中使用 @vite Blade 指令,指定卡片的 CSS 入口点:
<x-pulse>
@vite('resources/css/pulse/top-sellers.css')
...
</x-pulse>CSS 文件
对于其他用例(包括包内的 Pulse 卡片),可在 Livewire 组件上定义返回 CSS 文件路径的 css 方法,指示 Pulse 加载额外样式表:
class TopSellers extends Card
{
// ...
protected function css()
{
return __DIR__.'/../../dist/top-sellers.css';
}
}当此卡片包含在仪表盘上时,Pulse 会自动在 <style> 标签中包含此文件内容,无需发布到 public 目录。
Tailwind CSS
使用 Tailwind CSS 时,应创建专用的 Tailwind 配置文件,以避免加载不必要的 CSS,或与 Pulse 的 Tailwind 类发生冲突:
export default {
darkMode: 'class',
important: '#top-sellers',
content: [
'./resources/views/livewire/pulse/top-sellers.blade.php',
],
corePlugins: {
preflight: false,
},
};然后可在 CSS 入口点中指定该配置文件:
@config "../../tailwind.top-sellers.config.js";
@tailwind base;
@tailwind components;
@tailwind utilities;还需在卡片视图中包含与传入 Tailwind important 选择器策略 的选择器相匹配的 id 或 class 属性:
<x-pulse::card id="top-sellers" :cols="$cols" :rows="$rows" class="$class">
...
</x-pulse::card>数据捕获与聚合
自定义卡片可从任意位置获取和显示数据;但也可利用 Pulse 强大高效的数据记录和聚合系统。
捕获条目
Pulse 允许使用 Pulse::record 方法记录「条目」:
use Laravel\Pulse\Facades\Pulse;
Pulse::record('user_sale', $user->id, $sale->amount)
->sum()
->count();record 方法的第一个参数是所记录条目的 type,第二个参数是确定聚合数据如何分组的 key。对于大多数聚合方法,还需指定要聚合的 value。上述示例中,聚合的值是 $sale->amount。然后可调用一个或多个聚合方法(如 sum),以便 Pulse 将预聚合值捕获到「bucket」中,便于后续高效检索。
可用的聚合方法有:
avgcountmaxminsum
INFO
构建捕获当前已认证用户 ID 的卡片包时,应使用 Pulse::resolveAuthenticatedUserId() 方法,它会尊重对应用所做的任何用户解析器自定义。
检索聚合数据
扩展 Pulse 的 Card Livewire 组件时,可使用 aggregate 方法检索仪表盘中当前查看时段的聚合数据:
class TopSellers extends Card
{
public function render()
{
return view('livewire.pulse.top-sellers', [
'topSellers' => $this->aggregate('user_sale', ['sum', 'count'])
]);
}
}aggregate 方法返回 PHP stdClass 对象的集合。每个对象包含先前捕获的 key 属性,以及每个请求聚合的键:
@foreach ($topSellers as $seller)
{{ $seller->key }}
{{ $seller->sum }}
{{ $seller->count }}
@endforeachPulse 主要从预聚合 bucket 检索数据;因此,指定的聚合必须事先使用 Pulse::record 方法捕获。最旧的 bucket 通常会部分超出时段,因此 Pulse 会聚合最旧的条目以填补缺口,给出整个时段的准确值,而无需在每次轮询请求时聚合整个时段。
也可使用 aggregateTotal 方法检索给定类型的总值。例如,以下方法会检索所有用户销售的总值,而非按用户分组。
$total = $this->aggregateTotal('user_sale', 'sum');显示用户
处理以用户 ID 为键的聚合时,可使用 Pulse::resolveUsers 方法将键解析为用户记录:
$aggregates = $this->aggregate('user_sale', ['sum', 'count']);
$users = Pulse::resolveUsers($aggregates->pluck('key'));
return view('livewire.pulse.top-sellers', [
'sellers' => $aggregates->map(fn ($aggregate) => (object) [
'user' => $users->find($aggregate->key),
'sum' => $aggregate->sum,
'count' => $aggregate->count,
])
]);find 方法返回包含 name、extra 和 avatar 键的对象,可直接传递给 <x-pulse::user-card> Blade 组件:
<x-pulse::user-card :user="{{ $seller->user }}" :stats="{{ $seller->sum }}" />自定义 Recorder
包作者可能希望提供 recorder 类,让用户配置数据捕获。
Recorder 在应用 config/pulse.php 配置文件的 recorders 部分注册:
[
// ...
'recorders' => [
Acme\Recorders\Deployments::class => [
// ...
],
// ...
],
]Recorder 可通过指定 $listen 属性监听事件。Pulse 会自动注册监听器并调用 recorder 的 record 方法:
<?php
namespace Acme\Recorders;
use Acme\Events\Deployment;
use Illuminate\Support\Facades\Config;
use Laravel\Pulse\Facades\Pulse;
class Deployments
{
/**
* The events to listen for.
*
* @var array<int, class-string>
*/
public array $listen = [
Deployment::class,
];
/**
* Record the deployment.
*/
public function record(Deployment $event): void
{
$config = Config::get('pulse.recorders.'.static::class);
Pulse::record(
// ...
);
}
}