Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Top Laravel Package

leventcz/laravel-top

Lightweight real-time monitoring for Laravel apps directly from the command line. Run php artisan top to track essential metrics and busiest routes in production, with aggregated Redis data across all servers.

View on GitHub
Deep Wiki
Context7

Getting Started

Preflight (5 minutes). Confirm you meet: PHP 8.2+, Laravel 10–13, Redis 5.0+, and a working Redis connection already defined in config/database.php. Top does not create a connection for you — it borrows one.

composer require leventcz/laravel-top
php artisan vendor:publish --tag="top"   # optional, but do it

Pick your Redis target before you run anything. The default (TOP_REDIS_CONNECTION=default) shares the connection your cache, sessions, and queues probably use. For anything beyond a local look, define a dedicated connection in config/database.php (or a dedicated logical database) and point Top at it. This is the one config decision that matters day-to-day.

First use case — post-deploy smoke check. Run the command, then generate traffic:

php artisan top
# in another shell: hit your app, or run your smoke-test suite / k6 script
curl -s https://app.test/api/orders > /dev/null

The display is a rolling average of the last ~5 seconds, so it is empty until traffic has been flowing for a few seconds. Read it in this order:

  1. Busiest routes — which uri + method pair is taking the most requests. This is the table you came for.
  2. averageDuration per route — the column that turns "the app feels slow" into "GET /api/reports is slow."
  3. averageMemoryUsage per route — the sleeper metric. A route that spikes memory relative to its request rate is usually an unbounded eager-load or a large serialized payload.
  4. database() / cache() summaries — use these to route the investigation: high averageQueryPerSecond with high averageQueryDuration points at N+1s; low averageHitPerSecond on a cache you believe is warm points at key churn or a cache that isn't being hit.

Ctrl-C stops recording in the default runtime mode. It is a live instrument, not a recorder — there is nothing to look at "later."

Implementation Patterns

Pattern 1 — default runtime mode for everything diagnostic. Keep TOP_RECORDING_MODE=runtime (the default). It puts essentially nothing on the request path unless someone is actively recording, which is why this package is cheap to leave installed. Use it for deploys, incident triage, and "why is it slow right now" sessions.

Pattern 2 — opt in to recording from your own code. runtime mode is not a limitation, because you can force a window explicitly:

use Leventcz\Top\Facades\Top;

Top::startRecording(30);   // record for the next 30 seconds
// ... drive traffic ...
Top::isRecording();
Top::stopRecording();

This is the cleanest CI pattern: leave recording_mode at runtime in production, and let a CI script or a bespoke Artisan command open a recording window, fire the endpoints under test, and assert thresholds. You get the gate without making Top a permanent request-path dependency.

Pattern 3 — a thin Artisan command as your CI/deploy gate. Wrap the facade so the assertion lives in one place and is reviewable:

// app/Console/Commands/PerfGate.php  (sketch)
Top::startRecording(10);
Http::get('/api/orders');                 // or replay a k6/curl script
sleep(6);                                 // let the 5s window fill

$http = Top::http();
$worst = Top::routes()->sortByDesc('averageDuration')->first();

if ($http->averageDuration > 250) {       // ms
    $this->error("avg duration {$http->averageDuration}ms");
    return self::FAILURE;
}
$this->info("worst route: {$worst->method} {$worst->uri} @ {$worst->averageDuration}ms");

Treat this as a regression smoke alarm, not an SLI. Averaging makes it robust enough to catch a 3× regression and too blunt to catch a 20% one.

Pattern 4 — multi-server triage. Because aggregates live in shared Redis, one terminal reflects the whole fleet. That is the feature to lean on: during an incident, you do not need to SSH into each app server or wait for a dashboard. Run php artisan top from a bastion (or via whatever channel your platform gives you to run Artisan in production) and read fleet-level numbers.

Pattern 5 — facade inside an internal dashboard or Slack bot. Top::http(), Top::database(), Top::cache(), and Top::routes() return plain data objects (Leventcz\Top\Data\Route has uri, method, averageRequestPerSecond, averageMemoryUsage, averageDuration). Rendering them into an internal status page is a few lines. Do this only on internal routes, and never in a hot path — each call is a Redis read.

Pattern 6 — decide by metric, not by tab. When Top::http()->averageDuration is up, check in this order: routes() for the offender → database() for query rate/duration → cache() for hit/miss balance. That ordering maps to the three most common causes (a slow handler, a query storm, a cold cache) and keeps triage short.

Gotchas and Tips

HTTP requests only. Queues, scheduled jobs, Artisan commands, and broadcast/websocket work are invisible. In most Laravel apps a real share of latency and failure lives in queues, so a clean top display is not evidence the application is healthy. State this in your runbook and pair Top with queue monitoring.

Averages hide tail latency. There are no percentiles. A route at a comfortable 80 ms average can still be timing out 1% of users. Use Top to find the suspect route, then reach for real percentiles/logs to confirm. Do not promote a Top reading into an SLO.

The 5-second window is noisy on bursty traffic. Low-RPS routes flicker between empty and alarming. Drive sustained, realistic load for at least 10–15 seconds before you believe a number, and re-run twice before filing a bug.

Redis eviction is the sharpest edge. If Top shares a cache database with an allkeys-lru policy, your aggregates can be evicted before they are read — you get gaps or zeros, not an error. Isolate Top on its own logical database, and confirm the eviction policy on whichever instance you choose.

Measure the always blast radius before you ship it. recording_mode=always writes on every request. Test in staging: what happens to request latency when Redis is slow, and what happens when Redis is down? In runtime mode the risk is contained; in always mode you have added a production request-path dependency and should pin the version and own the rollback.

Test always mode outside HTTP. Confirm what Top actually records (or doesn't) in queue workers and console commands before you build anything on facade calls made from those contexts.

Fleet averages dilute a single bad host. The shared-Redis design means one sick server is averaged against healthy ones. Great for "is the app slow," bad for "is this pod slow" — Top is not a per-instance instrument.

Ctrl-C is destructive to your view. No history, short TTLs, nothing to replay. If a metric matters, capture it (dump to a file, log the array) while the window is open.

Production Artisan access may be your real blocker. Many managed platforms restrict shell access. Confirm you can run php artisan top (or a wrapped command) against production before the incident, not during it. This is a prerequisite, not a nice-to-have.

Route URIs land in Redis. Parameterized paths can expose customer IDs or resource names to anyone with access to that Redis instance. Check what your URIs look like and who can read the Top database.

Version pinning is on you. Single maintainer, small adoption base, and each Laravel major (12, then 13) required its own compatibility release. Pin the version and add leventcz/laravel-top to your Laravel upgrade checklist alongside other pinned packages. Removal is trivially clean — one Composer package, one config file.

Know the extension points, because there aren't many. You can publish the config, choose the Redis connection, choose the recording mode, and drive recording through the facade. There are no public hooks to add queue or job listeners — if you need that, you are writing your own listeners into the same Redis keyspace, and you own the compatibility risk.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core