dyanakiev/laravel-logger-discord-channel
A Laravel logging channel that sends application logs directly to Discord via webhook. Add it to your logging stack as a Monolog channel to receive formatted log messages in a Discord server, making errors and important events easy to monitor in real time. Simple configuration for quick alerts.
composer require dyanakiev/laravel-logger-discord-channel. Laravel's package discovery registers the service provider automatically; there is nothing to publish unless you want to tweak defaults.config/logging.php:'discord' => [
'driver' => 'discord',
'webhook' => env('DISCORD_WEBHOOK'),
'level' => env('LOG_DISCORD_LEVEL', 'error'),
'username' => 'Laravel ' . env('APP_NAME'),
'avatar' => '',
],
'stack' => [
'driver' => 'stack',
'channels' => ['daily', 'discord'],
],
LOG_CHANNEL=stack and LOG_DISCORD_LEVEL=error and let uncaught exceptions, report() calls, and failed jobs land in Discord while files keep the full detail. Run php artisan config:clear and trigger a throwaway Log::error('test') to confirm delivery before relying on it.config/logging.php and your .env; most "it doesn't work" reports are a stale config cache or a missing LOG_CHANNEL. The package source (DiscordHandler, the custom driver class) is small enough to read in a few minutes when you need to trace formatting behaviour.Tiered channels by severity. Define two or more channels so routine noise doesn't drown urgent alerts:
'discord_errors' => ['driver' => 'discord', 'webhook' => env('DISCORD_WEBHOOK'), 'level' => 'error'],
'discord_debug' => ['driver' => 'discord', 'webhook' => env('DISCORD_WEBHOOK_DEV'), 'level' => 'debug'],
Then use discord_debug only in local/staging via LOGGING_DEPLOY or an env-driven override.
Stack with daily first. Keep ['daily', 'discord'] ordering so the file handler always writes even if the webhook call throws. This is your cheapest resilience measure and costs one array entry.
Explicit per-event routing. For "this specific event matters" rather than "everything at this level", log to the channel directly:
Log::channel('discord')->alert('Payment webhook signature mismatch', [
'order' => $order->id,
'ip' => $request->ip(),
]);
This bypasses the stack threshold and gives you intent-revealing code that greps well.
Exception reporting hook. Rather than editing each catch, centralise in bootstrap/app.php (or app/Exceptions/Handler.php on older skeletons) by reporting to the Discord channel for production only:
->withExceptions(function (Exceptions $exceptions) {
if (app()->isProduction()) {
$exceptions->report(function (Throwable $e) {
Log::channel('discord')->error($e->getMessage(), ['exception' => $e]);
});
}
})
Context discipline. Discord messages are plain text; context arrays are JSON-encoded into the payload. Send a tight, stable shape (ids, job name, attempt number) rather than $request->all(). Think "what do I need at 3am on a phone screen" — not "what do I have".
Queued delivery for high volume. If you log to Discord from inside queue workers or high-traffic endpoints, route through a small queued job/Mailable-style wrapper so webhook latency and rate limiting never sit on the request path. discord as a stack member behind a queue is safer than direct logging in hot loops.
Environment plumbing. Add DISCORD_WEBHOOK and LOG_DISCORD_LEVEL to .env.example, and remember config:cache on deploy — env reads inside config/logging.php are baked at cache time, so use env() only there, never config() lookups that change per request.
Integration with monitoring. Use Discord for human-facing alerts (deploy finished, queue backlog, cert expiring) and keep Sentry/Flare for stack-trace forensics. Duplicating full exception dumps into Discord burns your 10-embeds-per-message budget fast.
debug-level channel in production will get you silently dropped or 429'd. Keep production on error or higher, or split traffic across multiple webhooks.$e->getTraceAsString() or send only the first N frames.level is a minimum, not an exact match. 'level' => 'error' also forwards critical, alert, emergency. Developers often expect filtering to be exact and are surprised by the volume.php artisan config:clear (or rely on the deploy script's config:cache) — otherwise you'll debug a channel that is still posting to last week's webhook.username and avatar are cosmetic but rate-limited too. Changing the avatar URL on every log line prevents Discord from caching it and can accelerate throttling; set it statically.* emphasis can render unexpectedly. Prefer \``\n...\n```` fences around payload dumps.^10 || ^11 || ^12 || ^13 (verify the exact string in composer.json before upgrading). If you have a pinned illuminate/support on an older major, the lockfile may still resolve fine — but run composer update dyanakiev/laravel-logger-discord-channel deliberately rather than a blanket update so you can read the diff.error tier and never in a tight loop.app()->environment() and a release hash before it leaves the app.How can I help you explore Laravel packages today?