Skip to content

Pulse ​

A performance dashboard of the site: slow pages by template, slow queries, servers.

kitloom/pulse · admins: kitloom/pulse-filament, kitloom/pulse-nova

Video lessons ​

Recorded in the Filament admin; the Nova admin works the same way.

Pulse Settings

A performance dashboard for a kitloom site: Laravel Pulse (MIT), self-hosted, in the site's own database. It shows which pages and requests are slow, which database queries are slow, exceptions, queues, the cache, who uses the site most, and — with pulse:check running — the servers' CPU, memory and disk. The admin section is kitloom/pulse-filament or kitloom/pulse-nova; the dashboard itself is Pulse's own page, /pulse. Installing the package is enough.

The dashboard ​

Pulse → Dashboard in the admin opens it in a tab of its own. Each card shows the last hour by default; the period switch at the top shows 6 hours, 24 hours or 7 days.

Who opens it: whoever holds the View the Pulse dashboard permission (view_pulse) — administrators from the start. Give it to another role on the roles screen, and a developer watches the site's performance without being able to change its settings. Pulse itself would open the page only on a developer's machine (APP_ENV=local); the module defines Pulse's viewPulse gate instead.

Slow pages ​

Every page of the site goes through one route, so Pulse's own Slow Requests card would list them all as one line, /{fallbackPlaceholder}. The module names a page the way WordPress's template hierarchy sees it, and the Slow Pages card lists them by template — how many were slow, the average and the slowest time:

PageIts name
A post, a book, a productsingle-post, single-book, single-product
A page / the front pagepage / front-page
The bloghome
A category, a tag, a term of another taxonomycategory, tag, taxonomy-genre
An archive of a post typearchive-book
An author, a date archiveauthor, date
Searchsearch
Not found404

The Slow Requests card lists the same pages by these names (with the HTTP method), next to the admin's and other routes, which keep their addresses. A page served from the page cache is not resolved again and keeps the route's name — and is rarely slow.

Settings ​

Pulse → Settings (the manage_options permission, like WordPress's own settings screens). Each field is an option in the options table; an empty field means Pulse's own configuration (its PULSE_* environment variables), shown as the placeholder.

FieldOptionWhat it does
Recordpulse_enabledOff — nothing new is stored; the dashboard keeps what it has. PULSE_ENABLED=false in the environment turns Pulse off entirely, and this switch cannot turn it back on.
Requests looked at, %pulse_sample_percentThe share of requests timed and counted (slow requests, slow pages, usage, cache interactions). Empty — 10 %, the module's default (see below); the cards scale the counts back up and mark them with ~.
Slow request, mspulse_slow_request_msA request or page that takes longer is listed as slow. 0 lists every one.
Slow query, mspulse_slow_query_msA database query that takes longer is listed as slow.
Keep data, dayspulse_keep_days1–7: Pulse deletes older data, and never keeps more than 7 days.

One request in ten by default. Pulse stores what its recorders saw at the end of every request it looks at, in a database transaction. On an ordinary page that is the cache reads, so without sampling every visit — a page served from the page cache too — ends with a write. The module therefore looks at 10 % of requests for the recorders that run on every request: Slow Requests (and Slow Pages), User Requests and Cache Interactions. Exceptions, slow queries, jobs and the rest are Pulse's as configured. The rate is kitloom-pulse.sample_rate (KITLOOM_PULSE_SAMPLE_RATE, 0.1); a rate other than Pulse's default of 1 that the application gives one of these recorders (PULSE_SLOW_REQUESTS_SAMPLE_RATE, PULSE_USER_REQUESTS_SAMPLE_RATE, PULSE_CACHE_INTERACTIONS_SAMPLE_RATE, or a published config/pulse.php) is kept for it, null or 1 leaves all of them at Pulse's own rate (every request), and a saved "Requests looked at" overrides both. A small site that wants every request counted sets the option to 100.

The status at the top says whether Pulse records, when it last stored anything, and whether pulse:check runs.

When a change applies. Pulse reads these at the moment it records or trims, and the module puts the options there at the start of every request and every queue job — so a save applies from the next request, under Octane as well, and from the next job in a queue worker. A long-running pulse:check keeps what it started with: restart it (php artisan pulse:restart). Whether Pulse runs at all (PULSE_ENABLED) is read while the application starts: a change of the environment needs php artisan config:cache again when the configuration is cached, php artisan octane:reload under Octane, and pulse:restart. When the options cannot be read, Pulse goes on with its own configuration, and the request is not affected.

AI agents ​

With kitloom/ai installed, an agent whose user has view_pulse reads the dashboard as numbers (pulse_report, over 1h, 6h, 24h or 7d): the slowest pages by template, slow routes, slow queries with the line that ran them, slow jobs and the exceptions thrown, each with how often and how slow. Only what Pulse keys by shape — queries with their ? placeholders, routes, templates, exception classes and where they were thrown. Slow outgoing requests are left out (an address may carry a service's key), and so are the users. kitloom-pulse.ai.register false — no such tool.

The Servers card: pulse:check ​

The Servers card is filled by a process that never ends and reports every 15 seconds: php artisan pulse:check. It is optional — without it the card stays empty, everything else works. To have it, run it on every server under Supervisor (or another process monitor):

ini
[program:pulse-check]
command=php /var/www/site/artisan pulse:check
autostart=true
autorestart=true
user=www-data
stopwaitsecs=30

After a deploy, php artisan pulse:restart makes it start over with the new code.

Deactivating Pulse on the Modules screen also stops loading laravel/pulse (unless the application requires it itself), its commands included: stop pulse:check (and pulse:work, with the Redis ingest) first, or the process manager keeps starting a command that is no longer there. The recorded entries stay in the database.

Storage ​

  • Pulse's tables — pulse_values, pulse_entries, pulse_aggregates under the connection's prefix (wp_pulse_*) — are created by php artisan migrate from Pulse's own migration. An application that published that migration (vendor:publish --tag=pulse-migrations) runs its copy instead; publishing it after the tables exist would create them twice, so don't.
  • Entries are stored at the end of each request with Pulse's storage ingest: no extra process. A busy site may move to Pulse's Redis ingest (PULSE_INGEST_DRIVER=redis plus php artisan pulse:work), as Pulse documents.
  • Pulse's own queries are left out of Slow Queries under their prefixed names as well.
  • Slow Queries asks the threshold the moment a query has run: a query under it costs a comparison, where Pulse would trace where every query came from and keep it until the end of the request. What it stores and its card are Pulse's.
  • The cards keep what they show for a few seconds in the cache, as PHP objects. When the application's cache unserializes no classes (cache.serializable_classes in config/cache.php, false in the skeletons as in Laravel 13's), the module keeps that cache in the request's memory instead (pulse.cache → array), so the dashboard works without an allow-list. PULSE_CACHE_DRIVER chooses a store yourself; it then has to bring Pulse's classes back.

What the application overrides ​

  • config/kitloom-pulse.php (php artisan vendor:publish --tag=kitloom-pulse-config): gate — false when the application defines viewPulse itself; page_names — false keeps Pulse's own slow requests recorder; dashboard.card — false serves Pulse's dashboard unchanged; check.seen_within — how recent a pulse:check report must be to count as running; filament.register, nova.register — the admin sections.
  • Pulse's own configuration (config/pulse.php, PULSE_*) works as Pulse documents: the path of the dashboard (PULSE_PATH), the recorders, their ignore and groups, per-route thresholds — an option sets only a threshold's default.
  • A published dashboard (vendor:publish --tag=pulse-dashboard) is the application's own: the module leaves it alone, and the card is added there by hand — <livewire:kitloom-pulse.slow-pages cols="6" />.
  • An application that binds Laravel\Pulse\Recorders\SlowRequests or Laravel\Pulse\Recorders\SlowQueries itself keeps its recorder.

Tests ​

From the application that installs the package: php vendor/bin/phpunit --testsuite Pulse. The skeletons switch Pulse off for every suite (PULSE_ENABLED=false); the module's tests switch it on for themselves.

kitloom — modules and themes for Laravel.
Pricing · Services · License · Refunds · Privacy · Community · [email protected]