jeffersongoncalves/laravel-discord-logger

Send Laravel logs to Discord with deduplication, configurable error grouping, rate limiting, async delivery and a graceful no-op when the webhook URL is missing.
1,843 3
Install
composer require jeffersongoncalves/laravel-discord-logger
Latest Version:v2.0.0
PHP:^8.2|^8.3|^8.4
License:MIT
Last Updated:Sep 10, 2026
Links: GitHub  ·  Packagist
Maintainer: jeffersongoncalves

Laravel Discord Logger

Laravel Discord Logger

Buy Me A Coffee

Latest Version on Packagist Tests Total Downloads License

Send Laravel logs to Discord — built for production. A Monolog channel with deduplication, configurable error grouping, rate limiting, async delivery with 429 backoff, and a graceful no-op when the webhook URL is missing.

Installation

composer require jeffersongoncalves/laravel-discord-logger

Publish the config (optional):

php artisan vendor:publish --tag="laravel-discord-logger-config"

Configuration

Add a channel to config/logging.php:

'discord' => [
    'driver' => 'custom',
    'via'    => \JeffersonGoncalves\DiscordLogger\Logger::class,
    'level'  => env('LOG_DISCORD_LEVEL', 'error'),
    'url'    => env('LOG_DISCORD_WEBHOOK_URL'),
],

Stack it onto your default channel so errors fan out:

'stack' => [
    'driver'   => 'stack',
    'channels' => ['single', 'discord'],
    'ignore_exceptions' => false,
],

Set the webhook (leave empty in local/testing — nothing will be sent, nothing will break):

LOG_DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/xxx/yyy

How the improvements work

Error grouping (fingerprint)

config/discord-logger.phpgrouping.strategy:

  • message — group by message text
  • level_message — group by level + message
  • exception (default) — group by exception class + file + line
  • a callback fn (\Monolog\LogRecord $record): string for full control

With grouping.normalize on, volatile tokens (numbers, UUIDs, hashes) are stripped before hashing, so User 123 not found and User 456 not found collapse together.

Deduplication

Within deduplication.window seconds, only the first occurrence of a fingerprint is sent. Repeats are counted silently. When the window closes, a single summary (🔁 occurred N×) is delivered — turn it off with deduplication.summary => false.

Rate limiting

  • rate_limit.global — hard cap on total messages app-wide
  • rate_limit.per_fingerprint — extra guard against a single looping error

Async delivery

Delivery runs through a queued job by default (queue.enabled). Discord 429s are retried respecting Retry-After; bad webhooks (4xx) fail fast instead of looping. Set queue.enabled => false to send inline (best-effort, errors swallowed).

This means a queue worker must be running (php artisan queue:work, Horizon, or supervisor) for Log::debug/info/error(...) calls to actually reach Discord. discord-logger:test sends inline and bypasses the queue entirely, so it will succeed even with no worker running — don't use it alone to confirm real logging works. If you don't run a worker (or don't want to), set DISCORD_LOGGER_QUEUE=false.

State store

Dedup + rate-limit counters live in the cache store named by store (null = default). Use Redis in production for atomic counters.

Per-level webhooks & mentions

Route a level to its own channel and ping someone when it matters:

'webhooks' => [
    'EMERGENCY' => env('DISCORD_LOGGER_WEBHOOK_ALERTS'),
    'CRITICAL'  => env('DISCORD_LOGGER_WEBHOOK_ALERTS'),
],

'mentions' => [
    'EMERGENCY' => '@here',
    'CRITICAL'  => '<@&123456789012345678>', // role id
],

allowed_mentions is set automatically, so @here / @everyone / role / user pings actually fire.

Context redaction

Sensitive data is masked before it ever reaches Discord, via two complementary strategies:

  • Key matching (redact) — case-insensitive key fragments whose values are masked. Defaults cover password, secret, token, authorization, api_key, apikey. Scrubbing recurses into nested arrays and the public properties of objects carried in the context.
  • Value patterns (redact_value_patterns) — PCRE regexes matched against scalar values, so a secret leaking under an innocuous key (e.g. url, auth) — or inside the message text and the stacktrace — is still caught. Defaults cover Bearer tokens and JWTs; leave the array empty to disable value-based redaction.

Fallback channel & safety

The handler never throws and is guarded against logging-while-logging recursion. If delivery throws, the error is swallowed; set fallback_channel (e.g. 'single') to record those failures instead of losing them.

Troubleshooting

discord-logger:test works, but Log::debug/info/error(...) never shows up in Discord.

The test command sends inline, straight to the webhook. Real log calls go through a queued job by default (see Async delivery), so nothing is delivered until a queue worker processes it. Fixes:

  • Run a worker: php artisan queue:work (or Horizon/supervisor in production), or
  • Set DISCORD_LOGGER_QUEUE=false to send inline instead (no worker needed).

This is especially easy to hit on a fresh Laravel install (Laravel 11+, including 13): QUEUE_CONNECTION defaults to database, but no worker runs automatically — jobs just sit pending in the jobs table.

Also check the channel's level in config/logging.php — if it's set above the level you're logging at (e.g. level => 'error' while calling Log::debug(...)), Monolog filters the record before it ever reaches the handler.

Commands

# Publish the config + optionally star the repo
php artisan discord-logger:install

# Send a test message to verify the webhook
php artisan discord-logger:test --channel=discord

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). See License File.

Related Packages

alitvinenko/laravel-pachka-logging

Send Laravel logs to Pachka messenger via webhook

1,092 0
skaisser/howl

Multi-driver Laravel notifier with Discord-first rich embeds, mentions, and bot-...

1,619 1
kidshenlong/monolog-influxdb

A handler for Monolog that sends messages to InfluxDB

13 4
hkar/monolog-bigquery-handler

A handler for Monolog that sends messages to Google BigQuery.

50 2
swayok/laravel-extended-errors

Extended laravel debug exceptions display (more info) and monolog's html emails...

1,370 1