spatie/laravel-health
Monitor your Laravel app’s health by registering checks (disk space, etc.) with warning/fail thresholds. Get notified via mail or Slack when checks degrade, and extend with custom checks for proactive alerting.
Installation:
composer require spatie/laravel-health
php artisan vendor:publish --tag="health-config"
php artisan vendor:publish --tag="health-migrations"
php artisan migrate
Register a Basic Check (e.g., disk space):
// In a Service Provider (e.g., AppServiceProvider.php)
use Spatie\Health\Facades\Health;
use Spatie\Health\Checks\Checks\UsedDiskSpaceCheck;
Health::checks([
UsedDiskSpaceCheck::new()
->warnWhenUsedSpaceIsAbovePercentage(70)
->failWhenUsedSpaceIsAbovePercentage(90),
]);
Schedule Checks (in app/Console/Kernel.php):
use Illuminate\Support\Facades\Schedule;
use Spatie\Health\Commands\RunHealthChecksCommand;
protected function schedule(Schedule $schedule)
{
$schedule->command(RunHealthChecksCommand::class)->everyMinute();
}
Verify Setup:
/health (default route).Check Registration:
DatabaseConnectionCheck, QueueCheck).
Health::checks([
new DatabaseConnectionCheck(),
new QueueCheck(),
]);
Check class or use closures:
Health::checks([
new class extends Check {
public function run(): Result {
return Result::ok('Custom check passed');
}
},
]);
Result Handling:
Result with ok(), warn(), or fail().Health::checks([
new CpuUsageCheck()
->warnWhenAbovePercentage(80)
->failWhenAbovePercentage(95),
]);
Notification Integration:
config/health.php:
'notifications' => [
'enabled' => true,
'notifications' => [
\Spatie\Health\Notifications\CheckFailedNotification::class => ['mail', 'slack'],
],
'mail' => ['to' => 'admin@example.com'],
'slack' => ['webhook_url' => env('SLACK_WEBHOOK')],
],
Result Storage:
EloquentHealthResultStore).'result_stores' => [
\Spatie\Health\ResultStores\InMemoryHealthResultStore::class,
],
API Endpoints:
/health.json?fresh=true./health (customizable theme: light/dark).Environment-Specific Checks:
QueueCheck in testing):
if (app()->environment('production')) {
Health::checks([new QueueCheck()]);
}
Dependency Checks:
Health::checks([
new class extends Check {
public function run(): Result {
return Http::get('https://api.stripe.com')->successful()
? Result::ok('Stripe API is reachable')
: Result::fail('Stripe API unavailable');
}
},
]);
Custom Notifiables:
Notifiable to send alerts to specific users/teams:
class TeamNotifiable extends \Spatie\Health\Notifications\Notifiable {
public function routeNotificationForMail(): array {
return ['admin@team.com'];
}
}
Then update config/health.php:
'notifiable' => \App\Notifications\TeamNotifiable::class,
Queue-Based Checks:
Health::checks([
new class extends Check {
public function run(): Result {
return (new HealthQueueJob($this))->dispatch()->wasSuccessful()
? Result::ok()
: Result::fail();
}
},
]);
Local Development:
InMemoryHealthResultStore to avoid cluttering the DB:
'result_stores' => [
\Spatie\Health\ResultStores\InMemoryHealthResultStore::class,
],
Notification Spam:
throttle_notifications_for_minutes in config/health.php (default: 60 minutes).'throttle_notifications_for_minutes' => 120, // 2 hours
Database Locks:
RunHealthChecksCommand executions may cause deadlocks.lockFor() in the command or limit scheduling frequency (e.g., every 2 minutes).Secret Leaks:
OH_DEAR_HEALTH_CHECK_SECRET in config..env:
OH_DEAR_HEALTH_CHECK_SECRET=your_secure_secret_here
Missing Migrations:
php artisan vendor:publish --tag="health-migrations" --force
php artisan migrate --force
Oh Dear Timeouts:
always_send_fresh_results or optimize checks:
'oh_dear_endpoint' => [
'always_send_fresh_results' => false,
],
Check Logs:
storage/logs/laravel.log for check execution errors.config/health.php (if available in future versions).Manual Check Execution:
php artisan health:checks
Result Inspection:
$results = Health::checks();
dd($results->all());
Slack/Mail Debugging:
php artisan queue:work --once # Check for failed jobs
php artisan queue:failed-table # Inspect failed notifications
Oh Dear Verification:
curl -X GET "http://your-app.test/oh-dear-health-check-results?secret=your_secret"
Custom Check Logic:
Check class to add logic (e.g., API rate limits):
class ApiRateLimitCheck extends Check {
public function run(): Result {
$limit = Http::get('https://api.example.com/limits')->json();
return $limit['remaining'] > 10
? Result::ok("API calls remaining: {$limit['remaining']}")
: Result::fail("Low API calls remaining: {$limit['remaining']}");
}
}
Result Storage Extensions:
class ElasticsearchHealthResultStore implements ResultStore {
public function store(HealthCheckResult $result): void {
// Custom logic to index results
}
}
Register in config/health.php:
'result_stores' => [
\App\ResultStores\ElasticsearchHealthResultStore::class,
],
Notification Channels:
class PagerDutyNotification extends Notification {
public function via($notifiable) {
return ['pagerduty'];
}
}
Register in config/health.php:
'notifications' => [
'notifications' => [
\App\Notifications\PagerDutyNotification::class => ['p
How can I help you explore Laravel packages today?