Weave Code
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

adamaru/monolog-fluentd-bundle

Symfony bundle adding a Fluentd handler to Monolog. Sends application logs to a Fluentd collector via host/port, with configurable level and bubbling. Integrates as a Monolog service handler for centralized logging and analysis.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require adamaru/monolog-fluentd-bundle
    

    Add the bundle to config/bundles.php:

    return [
        // ...
        Seretalabs\MonologFluentdBundle\MonologFluentdBundle::class => ['all' => true],
    ];
    
  2. Configure config/packages/monolog.yaml:

    monolog:
        handlers:
            fluentd:
                type: service
                id: monolog_fluentd.monolog_handler
    
  3. Configure Fluentd connection in config/packages/monolog_fluentd.yaml:

    monolog_fluentd:
        host: localhost
        port: 24224
        level: DEBUG
        bubble: true
    
  4. First Use Case: Inject the Monolog\Logger service and log:

    use Psr\Log\LoggerInterface;
    
    class MyService
    {
        public function __construct(private LoggerInterface $logger) {}
    
        public function doSomething()
        {
            $this->logger->info('test.fluentd', ['key' => 'value']);
        }
    }
    

Implementation Patterns

Core Workflows

  1. Structured Logging: Use the second argument of log methods (e.g., info(), error()) to pass structured data:

    $this->logger->error('user.login.failed', [
        'user_id' => 123,
        'ip' => $request->ip(),
        'timestamp' => now()->toIso8601String(),
    ]);
    

    Fluentd will forward this as a JSON payload with the log level as the tag.

  2. Contextual Logging: Attach context dynamically using Monolog’s pushContext():

    $this->logger->pushContext(['user_id' => $user->id]);
    $this->logger->info('action.performed');
    $this->logger->popContext(); // Remove context
    
  3. Conditional Logging: Use if ($this->logger->isEnabled($level)) to avoid unnecessary processing:

    if ($this->logger->isEnabled(Logger::DEBUG)) {
        $this->logger->debug('expensive.operation', ['data' => $expensiveData]);
    }
    
  4. Tagging Logs: Prefix log messages with a tag (e.g., service.name.event) to filter in Fluentd:

    $this->logger->info('order.processed', ['order_id' => 42]); // Tag: "order.processed"
    

Integration Tips

  • Symfony Events: Log events in event listeners/subcribers:

    public function onKernelRequest(GetResponseEvent $event)
    {
        $this->logger->info('kernel.request', [
            'method' => $event->getRequest()->getMethod(),
            'path' => $event->getRequest()->getPathInfo(),
        ]);
    }
    
  • Doctrine Events: Log database operations:

    public function onFlush(OnFlushEventArgs $event)
    {
        $this->logger->debug('doctrine.flush', [
            'entities' => count($event->getEntityManager()->getUnitOfWork()->getScheduledEntityInsertions()),
        ]);
    }
    
  • API Controllers: Log HTTP requests/responses:

    public function index(Request $request)
    {
        $this->logger->info('api.request', [
            'method' => $request->getMethod(),
            'route' => $request->getPathInfo(),
            'query' => $request->query->all(),
        ]);
        // ...
    }
    
  • Queue Workers: Track job processing:

    public function handle(Job $job)
    {
        $this->logger->info('job.started', ['job_id' => $job->id]);
        try {
            // Process job
            $this->logger->info('job.completed', ['job_id' => $job->id]);
        } catch (\Exception $e) {
            $this->logger->error('job.failed', [
                'job_id' => $job->id,
                'error' => $e->getMessage(),
            ]);
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Connection Issues:

    • Fluentd may not be running or misconfigured. Test connectivity with:
      telnet localhost 24224
      
    • Log connection errors by setting bubble: false in config and checking the main handler.
  2. Serialization Errors:

    • Non-serializable objects (e.g., closures, resources) in log context will cause crashes. Use json_encode() or getAttributes() for objects:
      $this->logger->info('user.data', [
          'user' => json_encode($user->toArray()),
      ]);
      
  3. Performance Overhead:

    • Network calls to Fluentd add latency. Avoid logging in tight loops or high-frequency operations (e.g., foreach iterations).
  4. Tag Collisions:

    • Reusing tags (e.g., error) across services may clutter Fluentd filters. Use namespaced tags (e.g., appname.error).
  5. Deprecated Bundle:

Debugging

  1. Check Fluentd Logs: Monitor Fluentd’s own logs (typically /var/log/td-agent/td-agent.log) for connection/rejection errors.

  2. Enable Monolog Debugging: Temporarily add a stream handler to debug locally:

    monolog:
        handlers:
            main:
                type: stream
                path: "%kernel.logs_dir%/%kernel.environment%.log"
                level: debug
            fluentd:
                type: service
                id: monolog_fluentd.monolog_handler
    
  3. Test with curl: Verify Fluentd is accepting logs:

    echo '{"json": "test"}' | nc localhost 24224
    

Configuration Quirks

  1. Default Level: The bundle defaults to DEBUG, but the monolog config may override it. Explicitly set:

    monolog_fluentd:
        level: INFO  # Override if needed
    
  2. Bubbling: Set bubble: false to prevent logs from propagating to parent handlers (useful for dedicated Fluentd handlers).

  3. SSL/TLS: The bundle does not support encrypted connections. For secure setups, use:

    • Fluentd’s forward plugin with TLS.
    • A reverse proxy (e.g., Nginx) to terminate TLS before Fluentd.

Extension Points

  1. Custom Formatter: Extend the handler to modify log structure before sending:

    use Seretalabs\MonologFluentdBundle\Handler\FluentdHandler;
    
    class CustomFluentdHandler extends FluentdHandler
    {
        protected function getDefaultFormatter()
        {
            return new \Monolog\Formatter\LineFormatter(
                "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n",
                null,
                true,
                true
            );
        }
    }
    

    Register as a service in config/services.yaml:

    services:
        monolog.handler.fluentd.custom:
            class: App\Logging\CustomFluentdHandler
            arguments:
                - '@monolog_fluentd.client'
            tags:
                - { name: monolog.logger, channel: 'main', handler: true }
    
  2. Dynamic Host/Port: Override the client dynamically (e.g., for multi-environment setups):

    $container->setParameter('monolog_fluentd.host', getenv('FLUENTD_HOST'));
    
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.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware