Skip to content

Health Monitoring

Health monitoring using Spatie Health package and Laravel Telescope for debugging.

The health monitoring system provides:

  • Health check endpoints for load balancers and monitoring
  • Dashboard UI for manual inspection
  • Email notifications for failures (throttled)
  • Historical data stored in database
Terminal window
# Via Artisan
./vendor/bin/sail artisan health:check
# Via HTTP
curl http://localhost/health

Navigate to /health-dashboard (requires authentication).

Check Purpose Threshold
Database PostgreSQL connectivity -
Cache Redis connectivity -
Disk Space Available storage Warn: 70%, Fail: 90%
Optimized App Laravel optimization status Production only
Debug Mode APP_DEBUG is false Production only
Environment APP_ENV matches expected Production only

Each check returns one of:

  • ok - Check passed
  • warning - Check passed with concerns
  • failed - Check failed
GET /health
Response (200 OK):
{
"finishedAt": "2025-11-14T17:30:00Z",
"checkResults": [
{"name": "Database", "status": "ok"},
{"name": "Cache", "status": "ok"},
{"name": "UsedDiskSpace", "status": "ok", "meta": {"used": "45%"}}
]
}
Response (503 Service Unavailable):
{
"finishedAt": "2025-11-14T17:30:00Z",
"checkResults": [
{"name": "Database", "status": "failed", "message": "Connection refused"}
]
}
GET /health-dashboard

Visual dashboard showing:

  • All check statuses
  • Historical trends
  • Failure details

File: config/health.php

return [
'result_stores' => [
Spatie\Health\ResultStores\EloquentHealthResultStore::class => [
'connection' => env('HEALTH_DB_CONNECTION', env('DB_CONNECTION')),
'model' => Spatie\Health\Models\HealthCheckResultHistoryItem::class,
'keep_history_for_days' => 1,
],
],
'notifications' => [
'enabled' => true,
'notifications' => [
Spatie\Health\Notifications\CheckFailedNotification::class => ['mail'],
],
'notifiable' => Spatie\Health\Notifications\Notifiable::class,
'throttle_notifications_for_minutes' => 60,
],
];

The notifiable is Spatie’s stock Notifiable — there is no custom class. The mail recipient comes from HEALTH_NOTIFICATION_EMAIL.

Terminal window
# Notification email
HEALTH_NOTIFICATION_EMAIL=ops@example.com
# Database connection for health checks
HEALTH_DB_CONNECTION=pgsql

Telescope provides debugging and monitoring for:

  • Requests
  • Commands
  • Jobs
  • Exceptions
  • Logs
  • Database queries
  • Cache operations
  • Mail
  • Notifications
GET /telescope

Requires authentication in production.

File: config/telescope.php

'enabled' => env('TELESCOPE_ENABLED', true),
'ignore_commands' => [
//
],
'ignore_paths' => [
'nova-api*',
],

Telescope data is pruned daily:

  • Keeps last 14 days
  • Preserves exception entries
  • Runs via scheduler
routes/console.php
Schedule::command('telescope:prune --hours=336 --keep-exceptions')->daily()->onOneServer();

Beyond health checks, the application ships with two observability tools.

Error and performance monitoring via sentry/sentry-laravel.

Config: config/sentry.php

Environment:

Terminal window
SENTRY_LARAVEL_DSN=
SENTRY_TRACES_SAMPLE_RATE=0.1

Captures exceptions and traces from web requests and queued jobs.

Application performance monitoring (Laravel Nightwatch). In staging/production the app streams events to a dedicated agent container (laravelphp/nightwatch-agent, defined in compose.yaml).

Environment:

Terminal window
NIGHTWATCH_TOKEN=
LOG_STACK=stderr,nightwatch

Event volume is trimmed by configureNightwatchFiltering() in AppServiceProvider, which rejects high-volume, low-value events (infrastructure table queries on jobs/cache/telescope_*/health history, the TestQueueJob and Telescope pending-updates jobs, and noisy scheduled commands like optimize and telescope:prune).

Source: backend/app/Providers/AppServiceProvider.php

use Spatie\Health\Checks\Check;
use Spatie\Health\Checks\Result;
class AerTicketApiCheck extends Check
{
public function run(): Result
{
try {
$service = app(AerticketCabinetService::class);
$service->testConnection();
return Result::make()->ok('AerTicket API is accessible');
} catch (\Exception $e) {
return Result::make()
->failed("AerTicket API unreachable: {$e->getMessage()}");
}
}
}
app/Providers/AppServiceProvider.php
use Spatie\Health\Facades\Health;
Health::checks([
// ... existing checks
AerTicketApiCheck::new(),
]);

When a check fails, CheckFailedNotification is sent over the mail channel to Spatie’s stock Notifiable, which routes to HEALTH_NOTIFICATION_EMAIL. Notifications are throttled to one per hour.

Terminal window
HEALTH_NOTIFICATION_EMAIL=ops@example.com

No custom notifiable class and no Slack channel are configured. Spatie supports a Slack channel out of the box if one is ever needed (see config/health.php).

  1. Run check manually:
Terminal window
./vendor/bin/sail artisan health:check
  1. Check specific service:
Terminal window
# Database
./vendor/bin/sail artisan tinker
>>> DB::connection()->getPdo();
# Cache
>>> Cache::get('test');
  1. Check authentication
  2. Verify route registration
  3. Check middleware configuration
  1. Check TELESCOPE_ENABLED=true
  2. Verify storage permissions
  3. Check database migration ran