Why PHP Monitoring Is Different
PHP applications have unique monitoring challenges compared to languages like Go or Java. The shared-nothing architecture means PHP has no persistent memory between requests — every request spins up a fresh process. There is no long-lived application state to watch. Instead, you need to monitor:
- PHP-FPM pool metrics — active processes, idle processes, max children reached
- OPcache hit rate — bytecode caching efficiency (should be >99%)
- Request-level metrics — latency per route, error rate, throughput
- External dependencies — MySQL slow queries, Redis latency, API call durations
- Queue health — Laravel Horizon or Beanstalkd queue depth and failure rate
The good news: because PHP is stateless, individual request failures don't cascade. The bad news: detecting slow memory leaks, OPcache thrashing, or FPM pool exhaustion requires explicit instrumentation.
Monitor Your PHP & Laravel App
Better Stack monitors your PHP application endpoints, sends alerts on downtime or slowness, and aggregates logs from PHP-FPM and nginx. Works with any PHP stack in minutes.
Try Better Stack Free →Layer 1: Uptime & HTTP Monitoring
Start with basic external monitoring before building internal metrics. An external uptime monitor tells you when your PHP app is unreachable from users' perspectives — independent of what your internal metrics say.
Health Check Endpoint
Add a /health endpoint that checks critical dependencies:
// routes/web.php (Laravel)
Route::get('/health', function () {
$checks = [];
// Database check
try {
DB::connection()->getPdo();
$checks['database'] = 'ok';
} catch (\Exception $e) {
$checks['database'] = 'error';
}
// Redis check
try {
Cache::store('redis')->get('health_check');
$checks['redis'] = 'ok';
} catch (\Exception $e) {
$checks['redis'] = 'error';
}
// Queue check (optional)
$checks['queue'] = Queue::size() < 1000 ? 'ok' : 'degraded';
$status = in_array('error', $checks) ? 503 : 200;
return response()->json([
'status' => $status === 200 ? 'ok' : 'degraded',
'checks' => $checks,
'timestamp' => now()->toIso8601String(),
], $status);
});Point your uptime monitor at this endpoint. Configure alerts for any non-200 response or response time >500ms.
Layer 2: PHP-FPM & Server Metrics
PHP-FPM has a built-in status page that exposes pool metrics. Enable it in your FPM pool config:
; /etc/php/8.3/fpm/pool.d/www.conf
pm.status_path = /fpm-status
ping.path = /fpm-ping
; Pool sizing — tune based on your server's RAM
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 15
pm.max_requests = 500 ; Restart workers after N requests to prevent memory leaksKey PHP-FPM metrics to watch at nginx_host/fpm-status:
| Metric | What to Watch | Alert Threshold |
|---|---|---|
| active processes | Requests being processed right now | Alert if active / max_children > 0.8 |
| max children reached | How often pool was fully saturated | Alert if incrementing (pool too small) |
| accepted conn | Total requests processed (rate) | Alert on sudden drops (FPM crashed) |
| listen queue | Requests waiting for an FPM worker | Alert if > 0 for more than 30s |
| slow requests | Requests exceeding request_slowlog_timeout | Alert if rate increasing |
OPcache Monitoring
// Expose OPcache stats as JSON endpoint (protect with auth middleware!)
Route::get('/metrics/opcache', function () {
$status = opcache_get_status(false);
return response()->json([
'hit_rate' => $status['opcache_statistics']['opcache_hit_rate'],
'memory_usage' => $status['memory_usage']['used_memory'],
'cached_files' => $status['opcache_statistics']['num_cached_files'],
'restarts' => $status['opcache_statistics']['oom_restarts']
+ $status['opcache_statistics']['hash_restarts'],
]);
})->middleware('auth:sanctum');OPcache hit rate below 95% indicates memory pressure or too many unique file paths. OPcache restarts (oom_restarts > 0) mean you need to increase opcache.memory_consumption.
PHP Log Aggregation Made Simple
Forward PHP error logs, nginx access logs, and Laravel logs to Better Stack Logs. Search across all logs in one place with real-time tail and structured search.
Try Better Stack Free →Layer 3: Application Metrics with Prometheus
For per-route latency histograms and custom business metrics, use Prometheus instrumentation.
Install Prometheus Client for PHP
composer require promphp/prometheus_client_phpLaravel-Specific: spatie/laravel-prometheus
For Laravel apps, the spatie/laravel-prometheus package is the easiest path:
composer require spatie/laravel-prometheus
# Publish config
php artisan vendor:publish --provider="Spatie\Prometheus\PrometheusServiceProvider"
# This auto-registers /prometheus endpoint
# Add custom gauges in AppServiceProvider:
Prometheus::addGauge('queue_size')
->helpText('Current queue depth')
->value(fn () => Queue::size());
Prometheus::addGauge('active_users_24h')
->helpText('Users active in last 24 hours')
->value(fn () => User::where('last_seen_at', '>', now()->subDay())->count());Middleware for Request Metrics
// app/Http/Middleware/PrometheusMiddleware.php
class PrometheusMiddleware
{
public function handle(Request $request, Closure $next): Response
{
$start = microtime(true);
$response = $next($request);
$duration = microtime(true) - $start;
$route = $request->route()?->getName() ?? 'unknown';
$status = $response->getStatusCode();
$method = $request->method();
// Record request count
Prometheus::getOrRegisterCounter(
'http_requests_total',
'Total HTTP requests',
['route', 'method', 'status']
)->inc([$route, $method, (string) $status]);
// Record duration histogram
Prometheus::getOrRegisterHistogram(
'http_request_duration_seconds',
'HTTP request duration',
['route', 'method'],
[0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0]
)->observe($duration, [$route, $method]);
return $response;
}
}Layer 4: Error Tracking
Sentry for PHP/Laravel
Sentry is the standard choice for PHP error tracking. Install and configure in minutes:
composer require sentry/sentry-laravel
# .env
SENTRY_LARAVEL_DSN=https://your-key@sentry.io/your-project
# config/sentry.php — set error sample rates
return [
'dsn' => env('SENTRY_LARAVEL_DSN'),
'traces_sample_rate' => 0.1, // 10% of requests for performance
'profiles_sample_rate' => 0.1,
];
# bootstrap/app.php (Laravel 11+)
->withExceptions(function (Exceptions $exceptions) {
$exceptions->report(function (Throwable $e) {
if (app()->bound('sentry')) {
\Sentry\captureException($e);
}
});
})Laravel Flare (Laravel-Native Alternative)
Flare integrates deeply with Laravel's Ignition error page for beautiful production error reports:
composer require spatie/laravel-flare
# .env
FLARE_KEY=your-flare-key
# Flare auto-captures: Exceptions, SQL queries on error,
# logs, jobs, and full request context
# No additional configuration required in most Laravel appsLayer 5: Laravel-Specific Tools
Laravel Telescope (Development & Staging)
Telescope provides an elegant dashboard for debugging in non-production environments:
composer require laravel/telescope --dev
php artisan telescope:install
php artisan migrate
# app/Providers/TelescopeServiceProvider.php
Telescope::night(); // Dark mode
# Record only slow queries in production (if you must enable it)
Telescope::filter(function (IncomingEntry $entry) {
if ($entry->type === EntryType::QUERY) {
return $entry->content['slow']; // Only slow queries
}
return $this->app->isLocal();
});Laravel Pulse (Production Monitoring)
Laravel Pulse is the production-ready alternative to Telescope with a much lower overhead:
composer require laravel/pulse
php artisan vendor:publish --provider="Laravel\Pulse\PulseServiceProvider"
php artisan migrate
# routes/web.php — protect the dashboard
Route::middleware(['auth', 'can:viewPulse'])->group(function () {
Route::get('/pulse', \Laravel\Pulse\Http\Controllers\DashboardController::class);
});
# Pulse tracks: Requests, Slow Requests, Slow DB Queries,
# Queue stats, Cache usage, Exceptions, Server metricsLaravel Horizon (Queue Monitoring)
composer require laravel/horizon
php artisan horizon:install
php artisan migrate
# Schedule snapshot for historical metrics
// app/Console/Kernel.php (Laravel 10) or routes/console.php (Laravel 11)
Schedule::command('horizon:snapshot')->everyFiveMinutes();
# Key Horizon metrics to alert on:
# - Failed jobs > 0 in last hour → page
# - Queue wait time > 30s → warning
# - Throughput dropping > 50% → warningLayer 6: Database Query Monitoring
Slow database queries are the #1 source of PHP application performance issues. Laravel makes it easy to detect them:
// AppServiceProvider.php boot() method
use Illuminate\Database\Events\QueryExecuted;
use Illuminate\Support\Facades\DB;
// Log slow queries
DB::listen(function (QueryExecuted $query) {
if ($query->time > 1000) { // > 1 second
Log::warning('Slow query detected', [
'sql' => $query->sql,
'bindings' => $query->bindings,
'time_ms' => $query->time,
'url' => request()->fullUrl(),
]);
// Optionally send to Sentry
\Sentry\addBreadcrumb(
category: 'db.query',
message: 'Slow query: ' . $query->time . 'ms',
level: 'warning',
);
}
});
// Enable query count in staging to catch N+1 problems
if (!app()->isProduction()) {
DB::enableQueryLog();
app()->terminating(function () {
$queryCount = count(DB::getQueryLog());
if ($queryCount > 50) {
Log::warning("N+1 suspected: {$queryCount} queries on " . request()->path());
}
});
}Alert Pro
14-day free trialStop checking — get alerted instantly
Next time PHP Application goes down, you'll know in under 60 seconds — not when your users start complaining.
- Email alerts for PHP Application + 9 more APIs
- $0 due today for trial
- Cancel anytime — $9/mo after trial
PHP APM Tools Comparison 2026
| Tool | Best For | PHP Support | Price |
|---|---|---|---|
| Blackfire.io | Performance profiling & CI integration | Excellent — PHP-native | From $24/mo |
| Tideways | Production PHP profiling & APM | Excellent — PHP-focused | From $19/mo |
| Datadog APM | Enterprise full-stack observability | Good auto-instrumentation | $31/host/mo+ |
| New Relic | Mature APM with long history | Good PHP agent | Free up to 100GB/mo |
| Scout APM | Simple developer-friendly APM | Laravel-native package | Free tier, $19.99/mo |
| OpenTelemetry | Open-source, any backend | Good, improving in 2026 | Free (self-hosted) |
| Sentry Performance | Combined errors + traces | Good, built into SDK | Free tier, $26/mo+ |
Recommendation: For most Laravel apps, start with Scout APM (free tier, Laravel package) for application-level traces and Sentry for error tracking. Add Blackfire.io if you need deep profiling for performance optimization. Graduate to Datadog when you need enterprise-grade observability across multiple services.
OpenTelemetry for PHP (2026)
OpenTelemetry's PHP SDK has matured significantly and is now a viable option for teams wanting vendor-neutral tracing:
composer require open-telemetry/sdk \
open-telemetry/exporter-otlp \
open-telemetry/opentelemetry-auto-laravel
# config/otel.php (or .env)
OTEL_PHP_AUTOLOAD_ENABLED=true
OTEL_SERVICE_NAME=my-laravel-app
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
OTEL_TRACES_SAMPLER=parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG=0.1 # 10% sampling
# The laravel instrumentation auto-instruments:
# - HTTP requests
# - Database queries (PDO)
# - Cache operations
# - Queue jobsEssential PHP Monitoring Alerts
Frequently Asked Questions
How do I add Prometheus metrics to a PHP application?
Use the promphp/prometheus_client_php library. Install via Composer: composer require promphp/prometheus_client_php. Create a CollectorRegistry, register counters/gauges/histograms, and expose them on a /metrics endpoint using TextRenderer::renderMetrics(). For Laravel, the spatie/laravel-prometheus package wraps this with automatic route and middleware registration. Key metrics to track: request count (Counter with route and method labels), request duration (Histogram with latency buckets), queue depth (Gauge), cache hit rate (Counter).
What is Laravel Telescope and should I use it in production?
Laravel Telescope is an elegant debug assistant that records requests, exceptions, database queries, queue jobs, mail, notifications, cache operations, and scheduled tasks. It is excellent in development and staging. For production: use it only if your database can handle the write load (it logs every request). Enable the slowLog option to only record slow operations. Use telescope:prune in your scheduler to prevent database bloat. Consider Pulse (Laravel's newer lightweight dashboard) for production monitoring as it is designed for lower overhead.
How do I track PHP errors in production?
The best options for PHP error tracking are: (1) Sentry — install sentry/sentry-laravel, configure DSN, automatic exception capture with stack traces and user context. (2) Flare — Laravel-native, integrates with Ignition for beautiful exception reports. (3) Bugsnag — good for multi-language teams. For Laravel, configure the report() callback in bootstrap/app.php to send exceptions to your provider. Set thresholds (e.g., only report errors, not warnings) to avoid alert fatigue.
What PHP APM tools are available?
Top PHP APM tools in 2026: (1) Datadog APM — excellent PHP tracing, auto-instrumentation for Laravel, high cost. (2) New Relic — mature PHP agent with detailed transaction tracing. (3) Blackfire.io — PHP-specific profiler, excellent for performance optimization, not full APM. (4) Tideways — PHP-focused APM with good Laravel support. (5) OpenTelemetry PHP SDK — open-source, export to any backend (Jaeger, Tempo). (6) Scout APM — simple, developer-friendly with a generous free tier. For most Laravel apps, Scout APM or OpenTelemetry are the best value.
How do I monitor Laravel queues?
Monitor Laravel queue health with: (1) Laravel Horizon — built-in dashboard for Redis queues with metrics on throughput, wait time, failed jobs. Add horizon:snapshot to your scheduler for metrics history. (2) Prometheus metrics via spatie/laravel-queue-monitor — exposes queue size, failed job count as Prometheus gauges. (3) Failed job alerting — use queue:failed notifications in Laravel, or a scheduler job that runs php artisan queue:failed | wc -l and alerts when > 0. Critical queue metrics: queue depth (alert if > N), failed job rate, job processing time (alert on P95 spikes).
Add Production Monitoring to Your PHP App
Better Stack monitors your PHP endpoints, aggregates your logs, and sends on-call alerts when things break. Works with any PHP framework — Laravel, Symfony, WordPress, or plain PHP.
Try Better Stack Free →