laraxgram/watchdog
LaraxGram Watchdog is a Laravel monitoring package that watches your app’s health and sends Telegram alerts when errors, failed jobs, or other issues occur, helping you catch problems early and keep production stable.
Watchdog is a Laravel log-monitoring package that tails your application logs and pushes formatted reports into Telegram, with a panel for browsing what has been captured. v1.3.0 is an incremental feature release (new context payloads, repeat collapsing, panel fixes) — there are no breaking changes, so upgrading is a composer update away.
Install and publish:
composer require laraxgram/watchdog
php artisan vendor:publish --tag="watchdog-config"
Check whether the package ships migrations (php artisan vendor:publish --tag="watchdog-migrations" && php artisan migrate) — the panel and repeat counter imply persisted log records, so run migrations before opening the UI.
Where to look first: the published config/watchdog.php. Confirm the log source path (storage/logs/laravel.log by default), the Telegram credentials (bot token + chat_id), the minimum log level you care about, and whether dispatch is queued or synchronous. Set WATCHDOG_BOT_TOKEN and WATCHDOG_CHAT_ID in .env rather than hardcoding them.
First use case — get one message into a chat. Create a bot with @BotFather, add it to the target chat/group, grab the chat ID, then trigger a test:
php artisan watchdog:test # or whichever test/report command the package exposes
Confirm delivery before wiring up the scheduler. Nothing is more confusing than debugging log parsing when the real problem is a bot that was never added to the group.
Make it automatic by scheduling the watcher in routes/console.php (Laravel 11+) or Kernel::schedule():
Schedule::command('watchdog:watch')->everyMinute()->withoutOverlapping();
Attach context at the source, not in the report. The headline feature in 1.3.0 is context being carried into Telegram report messages. That means anything you pass to Log::withContext() — or the context array on a log call — now surfaces in the chat. The idiomatic pattern is a middleware that tags every request:
Log::withContext([
'request_id' => (string) Str::uuid(),
'user_id' => auth()->id(),
'route' => request()->route()?->getName(),
]);
Now every alert arriving in Telegram is self-identifying, and you can jump straight from a notification to the relevant request in your logs.
Let the repeat counter do the deduplication. The new log repeat counter collapses identical consecutive entries into a single report with a count rather than N separate messages. This is the difference between a usable channel and one you mute after a week. Design around it: a tight loop throwing the same exception 500 times should produce one message saying so. If you want distinct events to stay distinct, make sure they differ in something Watchdog considers part of the entry (message, level, or context) — don't rely on timestamps alone.
Route by severity. Use separate chats or topics for error/critical versus warning/info. Most teams run two scheduler entries with different --level thresholds, so the on-call channel stays high-signal while a second, quieter channel absorbs routine noise.
Pair it with your existing channels, don't replace them. Keep stack in logging.php writing to daily files and Sentry/Flare; let Watchdog be the human-facing layer. It reads logs, it doesn't need to become the only destination.
Use the panel as a triage view. After the 1.3.0 panel fix, the UI is worth wiring into an admin-only route group behind your existing auth middleware. It's the fastest way to see whether a burst of alerts is one repeated error or genuinely many distinct ones — which is exactly the distinction the repeat counter is answering in the chat.
Guard the scheduler in multi-server setups. If you run more than one app server, either constrain the watcher to a single host (->onOneServer() with a shared cache lock) or accept duplicated reports. The latter gets old fast.
Log::withContext() — user IDs, emails, tokens accidentally logged in a request payload — will be transmitted to Telegram. Audit what you attach, and consider a redaction step in your middleware for known-sensitive keys before upgrading.MarkdownV2/HTML parse modes, and exceptions/messages frequently contain _, *, backticks, or angle brackets. If reports stop arriving, switch the parse mode to plain text as a first diagnostic.daily rotation, truncation, or logrotate copying. If alerts suddenly go quiet or replay old entries after midnight, that's the culprit — check whether the package handles inode/rotation changes or whether you should point it at a stable filename.storage/logs; a CLI-run scheduler as a different user may not be able to read it. Verify with sudo -u www-data php artisan watchdog:test if messages only work from your terminal.withoutOverlapping() plus a long backfill can silently skip runs. If you're catching up on an existing large log file, run it interactively first, then enable the schedule.Watchdog::beforeSend()-style hook. Customising the message layout there is far cheaper than patching the Telegram transport, and it survives package updates.How can I help you explore Laravel packages today?