wamesk/laravel-telescope
A Laravel package that integrates with Telescope to provide debugging and monitoring insights for your application. Inspect requests, queries, jobs, and logs from a convenient dashboard to diagnose issues faster during development and keep an eye on application behavior in real time.
This is a Laravel Telescope distribution, so the day-to-day value is: install it, point it at your app, and use it as your first stop when debugging a request, query, job, or exception.
composer require wamesk/laravel-telescope --dev
php artisan telescope:install # publishes config/telescope.php, migrations, assets
php artisan migrate
php artisan telescope:publish # only if you need to refresh published assets/config
Then open /telescope in local and browse the Requests, Queries, Jobs, and Exceptions watchers.
Where to look first:
config/telescope.php — enabled, driver, storage.database, and the watchers array. Disable noisy watchers here before you drown in entries.app/Providers/TelescopeServiceProvider.php — this is where you register the gate, Telescope::filter(), and Telescope::tag(). Almost every customization you need lives here.php artisan telescope:prune --help — retention is the operational half of Telescope, and it is the part that bites people in CI/staging.First use case: enable it locally, reproduce a slow endpoint, inspect the request's query timeline, then schedule pruning on staging so the telescope_entries table does not grow unbounded:
// routes/console.php or bootstrap/app.php
Schedule::command('telescope:prune', ['--hours' => 72])
->dailyAt('01:30')
->onOneServer();
Environment scoping. Keep the dependency in require-dev and gate it:
// TelescopeServiceProvider::register()
Telescope::filter(function (IncomingEntry $entry) {
if (app()->isLocal()) {
return true;
}
return $entry->isReportableException()
|| $entry->isFailedJob()
|| $entry->isScheduledTask()
|| $entry->hasMonitoredTag();
});
Watcher tuning instead of blanket enabling. In config/telescope.php, set QueryWatcher.only_slow with a slow threshold (e.g. 100ms) and disable RedisWatcher/EventWatcher if you don't need them. On a busy staging box this is the difference between a usable UI and a 20GB table.
Scheduled pruning is the primary operational workflow. This is exactly what 2.2.0 hardens:
Schedule::command('telescope:prune', ['--hours' => 48])
->dailyAt('01:30') // not 00:00 — see Gotchas
->onOneServer();
The 2.2.0 fix does two things worth knowing: it avoids running the prune at exactly midnight (where the hours cutoff and any daily rollups can straddle a date boundary), and it retries when the prune lock is already held. That means if you run multiple app servers and the lock is briefly contended — or a previous prune is still deleting rows — the command backs off and retries instead of failing the scheduled run. You can still keep ->onOneServer(); the retry is a safety net, not a replacement.
Manual/one-off pruning. php artisan telescope:prune --hours=24 for a targeted cleanup after a load test, and php artisan telescope:clear when you want a hard reset (prune only removes rows older than the window).
Tagging for cross-cutting investigation. Telescope::tag(fn ($entry) => $entry->user_id === $userId ? ['user:'.$userId] : null) lets you find all activity for a customer or a tenant from the UI, and pair it with hasMonitoredTag() in the filter so tagged entries survive in non-local environments.
Custom watchers as an extension point. Implement Laravel\Telescope\Watchers\Watcher (register() + record()), then register the class in config/telescope.php. This is the clean way to capture domain events (webhook deliveries, payment callbacks) alongside standard entries.
Production debugging without leaving it on. Gate /telescope with Telescope::auth(), and enable it only for a short window via a deploy flag or TELESCOPE_ENABLED=true in a canary environment. Treat it as a temporary instrument, not a permanent fixture.
00:00, shift it to 01:00–03:00; the fix protects the internal behavior, but a job scheduled at exactly midnight still lands in the ambiguous window for date-based logic.file cache store gives you per-host locks, so onOneServer() silently does nothing useful on a multi-node deploy. Use redis or database cache if you rely on the prune lock. The 2.2.0 retry handles transient contention — it does not make a non-shared lock shared.--hours is a cutoff, not a batch size. A very large table means a single prune run can be long. If you see lock retries stacking up (post-2.2.0 you'll see log lines rather than a hard failure), lower the retention window or prune more frequently with a smaller --hours value.telescope:prune compares against stored timestamps; if app.timezone and the server clock differ from your scheduler assumptions, your "48 hours" is not 48 hours. Keep the app timezone explicit and check config/app.php.TELESCOPE_ENABLED=false in the production .env is the baseline.telescope_entries_tags are deleted by the prune command too — if you prune aggressively, you lose the ability to search historical tagged entries.-v, check storage/logs/laravel.log, confirm the lock isn't stuck in the cache (redis-cli keys '*telescope*'), and verify the rows you expect to be gone are actually older than the cutoff. In 2.2.0, a lock conflict now surfaces as a retry rather than an immediate failure, so absence of an error no longer proves the prune ran.How can I help you explore Laravel packages today?