LaravelAPMPHP 8 min read

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

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

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.

💡 In MonitorKit's APM tab, switch to the Stats subtab to see P50/P95/P99 latency broken down by endpoint. Sort by P95 to find your worst offenders first.

Slow queries

The APM waterfall shows every SQL query as a span. Look for:

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:

AlertMetric / TypeThreshold
High CPUcpu_percent> 85% for 5 min
Low diskdisk_percent> 85%
Host offlineHost Offline
nginx downService Downnginx
mysql downService Downmysql
php-fpm downService Downphp-fpm
redis downService Downredis

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 →