jeffersongoncalves/laravel-discord-logger
Send Laravel logs straight to Discord via webhooks. This package adds a ready-to-use Discord logging channel so errors and app events land in your server channels with clean, readable formatting.
Install the package and publish its config:
composer require jeffersongoncalves/laravel-discord-logger
php artisan vendor:publish --tag=discord-logger-config
Set the webhook in .env:
DISCORD_LOGGER_WEBHOOK=https://discord.com/api/webhooks/...
DISCORD_LOGGER_FALLBACK_CHANNEL=single
Register a Discord channel in config/logging.php:
'discord' => [
'driver' => 'discord',
'webhook_url' => env('DISCORD_LOGGER_WEBHOOK'),
'level' => env('LOG_LEVEL', 'error'),
],
The first practical use case is production error visibility: add Discord to a stack channel alongside your normal file log so exceptions and Log::error() calls land in an ops channel without changing application code.
'stack' => [
'driver' => 'stack',
'channels' => ['single', 'discord'],
],
Verify with a throwaway log call before wiring it into production:
Log::channel('discord')->info('Deployment smoke test', ['env' => app()->environment()]);
Look first at config/discord-logger.php for transport options and at config/logging.php for channel wiring. Check storage/logs/laravel.log when the Discord side misbehaves — after v2.2.1 the package writes Discord HTTP failures there when the fallback channel is single.
Use a stack channel for normal operation. Keep single/daily as the durable record and Discord as the notification surface. This avoids losing logs if Discord is rate-limited, misconfigured, or down.
Separate channels by audience and severity. A common pattern is discord-errors for production exceptions and discord-deploys for release notifications, each with its own webhook and level. Avoid using one webhook for both chatty info logs and critical alerts.
Log with structured context. Pass arrays rather than string concatenation; context renders cleanly in Discord and stays useful in file logs:
Log::channel('discord')->error('Payment failed', [
'order_id' => $order->id,
'gateway' => $gateway,
'exception' => $e->getMessage(),
]);
Use the exception handler for uncaught errors. In bootstrap/app.php (or App\Exceptions\Handler on older Laravel), let report() handle exceptions and rely on the stack channel. This prevents duplicate Discord messages from both report() and manual Log::error() calls in the same code path.
Use failed() for queued jobs. Queue failures are easy to miss; log from the job’s failed() method with the job payload and exception, or ensure the queue failed-job event is reported through the Discord stack.
Environment-specific webhooks. Point staging and production at different webhooks via env vars. Never share a production webhook with local development; local test messages drown real alerts.
Consider asynchronous delivery for high-traffic paths. Webhook calls are HTTP requests. For request-path logging, prefer queued logging or a sampled approach. For low-volume alerts (exceptions, deploys), synchronous delivery is usually fine.
Add a deployment smoke test. After deploy, send one known message to the Discord channel and assert the fallback log for failed deliveries. This catches deleted webhooks and rotated tokens before real incidents.
4xx responses are not retryable. A deleted webhook, wrong token, or invalid payload returns 4xx and will fail immediately. v2.2.1 improves this by writing the HTTP status and Discord’s message to the fallback_channel before the job fails, e.g. Discord responded with HTTP 404: Unknown Webhook. Set DISCORD_LOGGER_FALLBACK_CHANNEL=single locally to see these entries in storage/logs/laravel.log. Without a fallback configured, diagnosing a bad webhook is much harder.
Treat the webhook URL as a secret. It grants posting rights to the channel. Keep it in .env, not in committed config, and rotate it if exposed. The v2.2.1 fallback message redacts the webhook URL, but your own log context may not.
Discord rate limits are strict. Webhooks are limited per webhook/channel (roughly 30 requests per minute in common cases) and will return 429 with retry information. Do not route high-volume debug logs through Discord; reserve it for errors and operational events.
Respect payload limits. Discord message content is capped around 2000 characters, and embeds have their own limits. Long exception traces can be truncated or rejected. Log a concise message to Discord and rely on the file log for full stack traces.
Validate the fallback channel name. DISCORD_LOGGER_FALLBACK_CHANNEL must match a channel defined in config/logging.php. If it does not, the fallback write can itself fail. single is the safest default.
Clear config after changing env values. php artisan config:clear (and config:cache in production) is required after changing DISCORD_LOGGER_* values, especially on cached deployments.
Watch for double logging. If Discord is in a stack channel and you also call Log::channel('discord') explicitly in the same flow, the same event can be delivered twice. Pick one pattern per code path.
Test without hitting Discord. In tests, swap or fake the log channel, or set the webhook to an invalid local endpoint and assert on the fallback log. Avoid letting CI send real messages.
Extension points. Use the published config and Laravel’s logging channel definitions for most customization. If you need custom formatting or filtering, prefer a dedicated Monolog processor/formatter or a separate channel over modifying vendor code. The fallback channel behavior itself is the first place to look when delivery fails silently.
How can I help you explore Laravel packages today?