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 Fluentd Bundle Laravel Package

musement/monolog-fluentd-bundle

A Symfony bundle that connects Monolog to Fluentd, adding a configurable handler so PHP applications can forward structured logs to Fluentd for centralized collection, routing, and analysis.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the packages.

    composer require musement/monolog-fluentd-bundle
    

    This pulls in fluent/logger (the msgpack-over-TCP client) as the transport. You also need PHP's msgpack extension or the msgpack composer polyfill, plus monolog/monolog and symfony/framework-bundle.

  2. Enable the bundle in app/AppKernel.php (or config/bundles.php on modern Symfony):

    $bundles = [
        // ...
        new Musement\MonologFluentdBundle\MusementMonologFluentdBundle(),
    ];
    
  3. Look first at Resources/config/services.yml inside the bundle. That file defines the Monolog handler service id (e.g. musement_monolog_fluentd.handler) and the arguments the extension wires (fluentd_host, fluentd_port, fluentd_tag). Everything else is a thin wrapper over Fluent\Logger\FluentLogger.

  4. Minimal config. Configure the handler and attach it to Monolog:

    # config.yml
    monolog:
        handlers:
            fluentd:
                type: service
                id: musement_monolog_fluentd.handler
                level: info
                bubble: true
    

    Depending on the version, the bundle's own extension may also accept host/port/tag keys (musement_monolog_fluentd: { host: 127.0.0.1, port: 24224, tag: web }). Verify the exact key names against DependencyInjection/Configuration.php in the vendored bundle.

  5. First use case. Stand up a local fluentd (or fluent-bit) with a forward input on port 24224, a stdout match, and start your app. Once you see web.symfony events printing from fluentd, you have the end-to-end loop working. From there, add a match web.** @type elasticsearch (or S3, or Datadog) and you've externalised your logs without touching application code again.

Implementation Patterns

Reference an existing handler as a Monolog service. The bundle exposes a Monolog handler; you do not instantiate it manually. The most common integration is a named handler that only the channels you care about write to:

monolog:
    handlers:
        fluentd:
            type: service
            id: musement_monolog_fluentd.handler
            level: notice
            channels: ['!doctrine', '!event', '!debug']

Split tags per channel. Because FluentLogger::post($tag, $record) is cheap, run one handler per logical stream so fluentd routing stays trivial:

monolog:
    handlers:
        fluentd_app:
            type: service
            id: musement_monolog_fluentd.handler
            channels: ['app']
        fluentd_security:
            type: service
            id: musement_monolog_fluentd.handler
            channels: ['security']

If the bundle's handler takes the tag as a constructor argument, override the service definition in your own services.yml rather than duplicating the handler class.

Lean on structured context, not string formatting. The Fluentd handler forwards the record as an array (via the Monolog formatter), so $logger->info('Order paid', ['order_id' => $id, 'amount' => $amount]) becomes first-class fields in fluentd/Elasticsearch. Avoid line formatters — they defeat the point of a structured transport.

Attach processors for correlation. Add a Monolog processor that injects request_id, user_id, and app_env on every record. This is where most of the day-to-day value comes from: you get a shared identifier across the fluentd stream and your APM, without app code changes.

class RequestContextProcessor { 
    public function __invoke(array $record): array {
        $record['extra']['request_id'] = $this->ids->current();
        return $record;
    }
}

Keep a local handler as a fallback. Pair the fluentd handler with a local stream or fingers_crossed handler for error+ so a fluentd outage does not silently swallow failures:

handlers:
    fluentd: { type: service, id: musement_monolog_fluentd.handler, level: info }
    errors:  { type: stream, path: '%kernel.logs_dir%/error.log', level: error }

Test against a real forward socket. Run fluentd with a @type stdout output in a container, or point the handler at a throwaway nc -l 24224. Asserting the msgpack payload on the wire (or asserting the stdout line in fluentd) is far more reliable than mocking FluentLogger.

Gotchas and Tips

  • No retry, no buffer, no backpressure handling. fluent/logger opens a TCP connection and posts directly; if fluentd is down or slow the write can fail or block the request. Treat log delivery as best-effort: always keep a local fallback handler for errors, and consider a fluentd/fluent-bit sidecar close by (localhost) so latency is negligible.
  • Monolog type: service is mandatory. Using any other type with the handler's id will error out; type: service + id: is the only correct wiring. Also remember channels and level filters are applied by Monolog before the bundle handler sees the record — misconfigured filters are the #1 cause of "fluentd is running but I see nothing."
  • Tag format matters to fluentd routing. Fluentd matches on dot-delimited tags (app.security, app.payments), and a tag like my-app will not match my_app.**. Confirm the tag format the bundle emits and keep it consistent with your match blocks; check with fluent-cat if a message is flowing to the wrong output.
  • msgpack extension dependency. The fluent/logger codec needs msgpack. If you see Class 'MessagePack' not found or silent serialization errors, install/enable the extension (or the rybakit/msgpack polyfill) and confirm the runtime container has it, since CLI and FPM often differ.
  • Symfony version drift. The bundle targets Symfony 2/3 (services in YAML, AppKernel). On Symfony 4+ Flex you register it manually in config/bundles.php, convert the service yaml to your config/services.yaml, and confirm the bundle's own config is loaded with bin/console debug:container musement_monolog_fluentd.handler --show-arguments.
  • Connection behaviour under FPM/workers. FluentLogger keeps a socket per PHP process. Under long-running workers or high FPM churn you'll open and drop connections constantly; either accept it or route through a local fluent-bit/fluentd forward input so the connect cost stays on loopback.
  • Connection timeouts are not exposed in the bundle config. If a hung fluentd is stalling requests, set the connection timeout inside FluentLogger (its constructor/property) by overriding the service definition in your app's services.yml, rather than expecting a bundle key — the bundle mostly forwards host/port/tag.
  • Extension point is the handler class. If you need custom tagging per record or to attach environment-specific fields, extend the bundle's handler or decorate the service, and re-tag it as monolog.handler so Monolog picks it up. Do not edit the vendor file.
  • Debugging checklist before assuming a bundle bug: (1) debug:container shows the handler with the right host/port, (2) debug:event-dispatcher/debug:container shows it registered on Monolog, (3) tcpdump -i lo port 24224 shows bytes leaving the process, (4) fluentd's own log shows the input accepting events and the correct match firing. This splits "bundle misconfigured" from "fluentd misconfigured" in seconds.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin