vrok/monitoring-bundle
A monitoring bundle for PHP applications that provides health checks, metrics collection, and observability hooks, with configurable endpoints and integrations to help track uptime and performance in production.
This is a Symfony bundle, not a Laravel package — there is no service provider, no config/monitoring.php, and composer require alone will not register anything. As a Laravel developer you have two realistic paths:
For path 1, the minimal steps are:
composer require vrok/monitoring-bundle
Register it in config/bundles.php (Symfony Flex usually does this for you):
return [
// ...
Vrok\MonitoringBundle\VrokMonitoringBundle::class => ['all' => true],
];
Then publish/author the config under config/packages/ (the bundle's README will name the exact root key and options — typically the recipient address, sender, subject, and mailer/transport settings). Point it at your Symfony Mailer DSN via env (MAILER_DSN), not hardcoded values.
Where to look first, in order:
bin/console list — find the command the bundle registers (something like monitoring:alive / monitoring:send-alive). That command is the package.Command/ and Service/ directories in vendor/vrok/monitoring-bundle/. It's a tiny package; read it end-to-end in ten minutes before trusting it.config/packages/*monitoring*.yaml for the config tree.First use case: send one heartbeat email by hand.
php bin/console monitoring:alive -v
Confirm the mail arrives (use Mailpit/Mailhog locally, not a real inbox). Only once that works do you wire it into cron. The whole value proposition is: if these emails stop arriving, something is wrong — so the first milestone is a verified manual send, the second is a verified scheduled send, the third is a verified missing send (kill the cron and confirm your monitoring side actually alerts).
The heartbeat / dead-man's-switch pattern. The bundle's job is narrow: compose and send a fixed "I'm alive" message. The intelligence lives in the absence of mail. That means the correct integration is a cron entry, not a request hook:
*/15 * * * * cd /var/www/app && php bin/console monitoring:alive --no-interaction >> /var/log/monitoring.log 2>&1
Keep the interval comfortably inside your alerting window (e.g. every 15 min, alert after 45 min of silence) so a single transient mail failure doesn't page anyone.
One invocation per app/host. If you run several services, give each a distinct subject or recipient tag (app=api, app=worker, host=web-02). Most monitoring inboxes (healthchecks.io, Uptime Kuma push, a shared mailbox with filters) key off that. Sending the same subject from six hosts makes the alert ambiguous.
Lean on a scheduler rather than raw crontab where you can. In Symfony, the Scheduler component plus a single messenger:consume scheduler_default worker gives you versioned, testable schedules and --env handling. In Laravel, the direct port is trivial and is what I'd actually ship:
// app/Console/Commands/MonitoringAlive.php
public function handle(): int
{
Mail::raw('alive', fn ($m) => $m
->to(config('monitoring.address'))
->subject('alive: '.config('app.name').' '.gethostname()));
return self::SUCCESS;
}
// routes/console.php
Schedule::command('monitoring:alive')->everyFifteenMinutes()->withoutOverlapping();
That's ~15 lines and removes the dependency entirely — worth noting given the package's maturity.
Environment separation. Run the command in every environment you care about, but route non-production heartbeats to a separate inbox or tag them env=staging, otherwise staging noise trains you to ignore the alerts.
Exit codes matter more than the email. A cron line that returns 0 while the mail silently failed is worse than useless. Verify the command returns non-zero on transport exceptions, and keep the >> logfile 2>&1 redirect so cron failures are greppable.
Local testing. Assert on the mailer transport, not on a live send: in Symfony use symfony/mailer's test transport or a Mailpit container; in Laravel, Mail::fake(). Then run the command from a shell that mimics cron's minimal environment (see gotchas).
vendor/vrok/monitoring-bundle/ yourself. You're looking for: does it swallow mailer exceptions (bad — silence becomes a false "all good"), does it read config safely, does it hardcode anything, are there any @ error suppressors. Pin the version in composer.json and don't float it.PATH and no shell profile, so MAILER_DSN from your .env may not be loaded unless the app bootstraps Dotenv itself (Symfony does, but only with the right APP_ENV and working directory). Always cd into the project root in the cron line and pass --env=prod explicitly.*/15 is safe; 0 9 * * * style schedules shift by an hour twice a year. Prefer interval syntax for heartbeats and set CRON_TZ if it must align with wall-clock time.services.yaml (decorates: / alias override), or swap the transport through the Mailer DSN. If you need custom payloads (JSON, HTTP push instead of email), you're likely writing your own command — several monitoring services accept a plain HTTP GET, which is one curl and zero dependencies.DependencyInjection/Configuration.php for the actual node names and defaults rather than guessing — this is faster than debugging the YAML.How can I help you explore Laravel packages today?