How to monitor Laravel application performance in 2025
Set up request tracing, slow query detection, and server alerts for your Laravel app — without paying $34/host/month for Datadog.
Laravel is fast out of the box — until it isn't. A single N+1 query or a slow third-party API call can turn a 50ms response into a 2-second one, and most teams don't find out until a user complains or the server falls over.
This guide shows you how to add full observability to a Laravel application: distributed traces, slow query detection, infrastructure metrics, and alerts — in under 10 minutes.
What you'll set up
- APM tracing — every HTTP request, background job, and Eloquent query, visualized in a waterfall
- Infrastructure monitoring — CPU, memory, disk, and PHP-FPM pool metrics from your Linux servers
- Log aggregation — nginx, PHP-FPM, and application logs in one place
- Alerting — get notified by email or Slack when CPU spikes, a host goes offline, or a service stops running
Option A — Composer package (recommended for developers)
Install the MonitorKit Laravel package:
composer require monitorkit/laravel
Add your credentials to .env:
MONITORKIT_SERVER=https://your-monitorkit.co
MONITORKIT_KEY=mk_your_agent_key_here
MONITORKIT_SERVICE=my-laravel-app
MONITORKIT_ENABLED=true
That's it. The package auto-discovers itself via Laravel's service provider mechanism. Every HTTP request is now traced automatically — no middleware to register, no config to publish.
What's traced automatically
- All HTTP requests — method, route, status code, duration
- Eloquent and raw DB queries (once you enable query logging — see below)
- Queue jobs — dispatch time, processing time, failure status
- Cache operations — hits, misses, puts
- Outbound HTTP via Guzzle
- Exceptions and logged errors
Enabling Eloquent query tracing
Add one line to App\Providers\AppServiceProvider::boot():
public function boot()
{
if (env('MK_LARAVEL_DB_LOG')) {
\DB::enableQueryLog();
}
}
Then add to .env:
MK_LARAVEL_DB_LOG=true
All SQL queries now appear as spans in the APM waterfall with their duration and normalized statement (parameter values are automatically scrubbed to prevent PII leakage).
Option B — Zero-code install (for SysAdmins)
If you don't want to touch the application code — for example, when working with a legacy app or a strict deployment process — you can install the PHP APM agent at the system level:
MK_SERVER=https://your-monitorkit.co \
MK_KEY=mk_your_key_here \
MK_SERVICE=my-laravel-app \
bash <(curl -fsSL "https://your-monitorkit.co/static/install-php-agent.sh")
The installer writes a single PHP INI file (auto_prepend_file = /opt/monitorkit-apm/autoload.php) and reloads PHP-FPM. No application code changes, no deployment needed. Laravel routes are normalized automatically (e.g., /users/123 → /users/{id}).
Install the server agent
The server agent ships CPU, memory, disk, network load, and PHP-FPM pool metrics every 30 seconds. Install it on every server you want to monitor:
MONITORKIT_SERVER=https://your-monitorkit.co \
MONITORKIT_KEY=mk_your_key_here \
bash <(curl -fsSL "https://your-monitorkit.co/install-agent.sh")
The agent runs as a systemd service and restarts automatically on failure.
Key metrics to watch in Laravel
P95 response time by endpoint
The 95th percentile (P95) tells you what the slowest 5% of your users experience. A P50 of 80ms with a P95 of 2000ms means most users are fast but some are hitting something slow — usually an N+1 query or an external API call without a timeout.
Slow queries
The APM waterfall shows every SQL query as a span. Look for:
- Queries taking >100ms — usually missing indexes
- The same query repeating N times on a single request — the classic N+1 problem
- Queries inside loops (
foreach+ Eloquent lazy loading)
Queue job failure rate
Failed jobs don't appear in HTTP access logs. MonitorKit traces every JobProcessing and JobFailed event, so you see failed jobs in the APM tab with their error message and stack trace context.
PHP-FPM worker saturation
When all PHP-FPM workers are busy, new requests queue up and response time spikes. Enable PHP-FPM metrics in your agent config:
[phpfpm]
enabled = true
status_urls = ["http://127.0.0.1/fpm-status?json"]
You'll see active vs idle workers in real time on the host detail panel. Set a "Service Down: php-fpm" alert to get notified if the pool stops responding.
Setting up alerts
In the Alerts section of the dashboard, create these rules for a production Laravel app:
| Alert | Metric / Type | Threshold |
|---|---|---|
| High CPU | cpu_percent | > 85% for 5 min |
| Low disk | disk_percent | > 85% |
| Host offline | Host Offline | — |
| nginx down | Service Down | nginx |
| mysql down | Service Down | mysql |
| php-fpm down | Service Down | php-fpm |
| redis down | Service Down | redis |
Common issues and how to find them with APM
N+1 queries
You're loading a list of posts with their authors. Each post triggers a separate query to load its author. With 20 posts that's 21 queries instead of 1. Fix it by eager loading:
// Before — 1 + N queries
$posts = Post::all();
// After — 2 queries
$posts = Post::with('author')->get();
In the APM waterfall, N+1 problems appear as dozens of identical SQL spans. Sort by count in the slow queries table to find them.
Missing database indexes
A query like SELECT * FROM orders WHERE user_id = ? without an index on user_id does a full table scan. With 1M rows, this takes seconds. APM shows the query duration — anything over 100ms on a simple lookup is usually a missing index.
Synchronous external API calls
If your app calls a third-party API (payment gateway, email service, SMS) synchronously in the request cycle and that API is slow, your users wait. APM traces outbound HTTP calls — you'll see them as spans in the waterfall. Move slow external calls to queue jobs.
Next steps
Try MonitorKit free
Everything in this article — APM, server monitoring, alerts — in one tool. 14-day trial, no credit card.
Start free trial →