Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Monolog Discord Handler Bundle Laravel Package

thedomeffm/monolog-discord-handler-bundle

Symfony bundle providing a Monolog handler that sends log records to Discord via webhook. Configure a webhook URL and minimum log level to push errors and other records from your Symfony app into a Discord channel. Install with Composer and wire it into Monolog through the bundle's service configura...

View on GitHub
Deep Wiki
Context7

Getting Started

Install the bundle and its underlying handler with Composer:

composer require thedomeffm/monolog-discord-handler-bundle

This pulls in thedomeffm/monolog-discord-handler, the package that contains the actual DiscordHandler; the bundle is only Symfony DI/configuration glue around it.

1. Create the webhook. In the target Discord channel: Channel Settings → Integrations → Webhooks → New Webhook, pick the channel, and copy the URL. Treat it as a credential — anyone with it can post to the channel.

2. Store it in the environment. Never commit the URL:

# .env.local
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/123456/abcdef...

3. Register the bundle in config/bundles.php. Symfony Flex auto-registers symfony-bundle types, but verify the entry exists:

TheDomeffm\MonologDiscordHandlerBundle\MonologDiscordHandlerBundle::class => ['all' => true],

4. Wire a Monolog handler. The bundle exposes a discord Monolog handler type (confirm the exact key names against the package README, since documentation is thin):

# config/packages/prod/monolog.yaml
monolog:
    handlers:
        discord:
            type: discord
            webhook_url: '%env(DISCORD_DISCORD_WEBHOOK_URL)%'
            level: error

5. Verify. Trigger a log at or above the threshold and confirm the message lands in the channel:

bin/console cache:clear
bin/console monolog:test discord   # or simply trigger a real exception in prod scope

The first use case is the obvious one: a low-effort "errors and above go to #alerts" channel so the team sees production failures without opening a log aggregator.

Implementation Patterns

Environment-scoped enablement. Put the handler in config/packages/prod/monolog.yaml (and optionally staging) only. In dev, route to console/test handlers instead — you do not want local stack traces in a shared channel, and you do not want Discord rate limits hit by local dump()-driven logging.

Buffer with fingers_crossed. The most useful pattern is to not send anything until an error occurs, then flush the preceding context:

monolog:
    handlers:
        discord_buffer:
            type: fingers_crossed
            action_level: warning
            handler: discord_publish
        discord_publish:
            type: discord
            webhook_url: '%env(DISCORD_WEBHOOK_URL)%'
            level: debug

This gives you the log lines leading up to the failure in one Discord message (subject to the 2000-character message limit — see Gotchas).

Split channels by severity. Use two webhooks: #alerts for error and #on-call for critical/alert/emergency. Two named handlers in the same monolog.handlers block, each with its own webhook_url env var.

Route by channel name. If your app uses Monolog channels ($logger = $this->get('logger') with a channel name), add channels: [app, security] to the handler so infrastructure noise does not spam Discord.

Format for Discord, not for humans reading a file. Discord renders Markdown and code fences. Use a LineFormatter that produces something readable in a chat bubble:

discord_publish:
    type: discord
    webhook_url: '%env(DISCORD_WEBHOOK_URL)%'
    formatter: monolog.formatter.line
    # or a custom service formatter, e.g. app.monolog.discord_formatter

A custom Monolog\Formatter\FormatterInterface is the cleanest extension point: it lets you truncate, strip ANSI, redact secrets/passwords/card numbers, and decide whether to include extra/context. Register it as a service and reference it via formatter:.

Attach instead of embed for long payloads. If the handler exposes an attachment/use_attachment option, enable it for stack traces — Discord's per-message content limit is 2000 characters, and file uploads sidestep it. Verify support in the underlying handler's README before relying on it.

Deduplicate before sending. Discord webhooks allow roughly 30 messages/minute and 5 per 2 seconds per webhook. Wrap the Discord handler in Monolog\Handler\DeduplicationHandler (or a WhatFailureGroupHandler) so a tight error loop does not get your webhook temporarily banned:

discord_dedupe:
    type: deduplication
    handler: discord_publish
    time: 60

Fallback if the bundle stagnates. Because the bundle is thin, you can drop it and register the raw handler yourself:

services:
    app.monolog.discord_handler:
        class: TheDomeffm\MonologDiscordHandler\DiscordHandler
        arguments:
            - '%env(DISCORD_WEBHOOK_URL)%'
            - !php/const Monolog\Logger::ERROR

then reference it from Monolog with type: service / id: app.monolog.discord_handler. This is the escape hatch if the bundle's config tree or service definition breaks against a newer Monolog.

Testing locally. Point DISCORD_WEBHOOK_URL at a throwaway channel for integration testing, or swap the handler for test/null in the test environment. For unit tests, avoid exercising the real webhook; assert on the formatter output or mock the HTTP layer if the handler is injectable.

Gotchas and Tips

Maintenance risk is real. Two stars and zero dependents means this is effectively a one-person project. Before adopting, check the composer.json constraint on monolog/monolog — if it caps at ^2.0, it will conflict with Monolog 3 projects, and HandlerInterface signature changes there will break the handler. Pin the version and be prepared to vendor the fallback service definition above.

Monolog 3 compatibility. Monolog 3 changed AbstractProcessingHandler/HandlerInterface signatures and the Logger::* constants moved. A bundle built against Monolog 2 will either fail to install or throw a fatal error at handler instantiation. Test on a branch before upgrading Monolog.

The 2000-character message cap. Discord silently truncates or rejects oversized content payloads. Stack traces routinely exceed this. Either set an attachment mode, truncate in a custom formatter (keep the first ~1500 chars plus a marker), or accept losing the tail of the trace and rely on your log aggregator for the full picture.

Rate limits and retry storms. The handler will typically surface transport failures as exceptions bubbling out of Monolog. Wrap it in WhatFailureGroupHandler so a Discord outage cannot take down your request by throwing during logging:

discord_safe:
    type: whatfailuregroup
    members: [discord_publish]

bubble semantics in nested handlers. If Discord is the nested handler under fingers_crossed, bubble: false on the Discord handler prevents further propagation but can also suppress outer handlers depending on ordering. Keep bubble: true unless you have a specific reason, and verify by logging to two handlers in a test.

Secrets leak into Discord. By default Monolog's context includes request data. Discord is a third-party service — anything you send is stored in channel history. Redact tokens, passwords, cookies, and PII in the formatter, and consider a dedicated channel with restricted membership.

Webhook rotation. If the URL leaks, delete the webhook in Discord and redeploy with a new env var. Because the URL is treated as a plain string in %env()%, rotating requires a cache clear/redeploy, not just an env change (%env()% values are resolved at container compile time unless you use %env(...)% runtime placeholders carefully).

No batching out of the box. Each log record is one HTTP call. For high-volume services, put FingersCrossedHandler or DeduplicationHandler in front of it rather than sending every warning.

Debugging config errors. If Symfony complains about an unrecognized option under monolog.handlers.<name>, the bundle's Configuration.php tree is the source of truth — open vendor/thedomeffm/monolog-discord-handler-bundle/DependencyInjection/Configuration.php and read the allowed keys instead of guessing.

Extension points. Decorate the handler service if you need retry/backoff, or add a Monolog Processor to enrich every record with hostname, environment, and request_id so a Discord alert is actionable on its own. A processor is less invasive than subclassing the handler and survives bundle updates.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core