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

Laravel Fluent Logger Laravel Package

ytake/laravel-fluent-logger

Laravel package that integrates Fluentd logging into your app. Configure a Fluentd channel in config/logging.php and ship structured logs to your aggregator via fluent-logger, with a service provider and facade for quick, minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Install with Composer; the service provider is auto-discovered on Laravel 5.5+:

composer require ytake/laravel-fluent-logger

Pick the major line that matches your framework: 8.0.0 is the Laravel 12-compatible release (its changelog is limited to updating the test matrix for Laravel 12), 7.0.0 remains the line for older Laravel/Monolog combinations. If you are not yet on Laravel 12, constrain explicitly ("ytake/laravel-fluent-logger": "^7.0") rather than floating to ^8.0 in a bulk composer update.

Register a channel in config/logging.php. The package adds a fluent driver that wraps Fluent\Logger\FluentLogger (MessagePack over TCP to Fluentd's in_forward input):

'channels' => [
    'fluent' => [
        'driver' => 'fluent',
        'host'   => env('FLUENT_HOST', '127.0.0.1'),
        'port'   => env('FLUENT_PORT', 24224),
        'tag'    => env('FLUENT_TAG', 'laravel'),
        'level'  => env('LOG_LEVEL', 'debug'),
    ],
],

Then either make it the default (LOG_CHANNEL=fluent) or address it explicitly:

Log::channel('fluent')->info('order.created', [
    'order_id' => $order->id,
    'total'    => $order->total,
]);

Where to look first:

  • The package README for the exact driver name and supported options for your tagged version (the config surface has shifted across Laravel 5.x → 12).
  • Ytake\LaravelFluent\FluentServiceProvider — it calls Log::extend('fluent', …), so the channel config keys map directly to the FluentLogger constructor.
  • composer.json of the tagged release you install — the 8.0.0 release notes only mention test-suite work for Laravel 12, but a major bump is normally where laravel/framework, illuminate/support, and monolog/monolog constraints move. Confirm before assuming a drop-in upgrade.
  • Your Fluentd side: confirm <source> @type forward is listening on 24224 and that a <match **> output exists, otherwise the app sends successfully and logs still vanish.

First use case: ship structured application logs into Fluentd → Elasticsearch/Loki/BigQuery instead of scraping rotating files. Start with one channel (fluent) and one tag (laravel.dev), verify with fluent-cat and a stdout match before wiring it into production.

Implementation Patterns

Channel-per-domain, not one giant tag. Fluentd routing is tag-based, so use separate channels for separate consumers:

'channels' => [
    'fluent_app' => ['driver' => 'fluent', 'tag' => 'app.'.env('APP_ENV'), ...],
    'fluent_audit' => ['driver' => 'fluent', 'tag' => 'audit.'.env('APP_ENV'), ...],
    'fluent_billing' => ['driver' => 'fluent', 'tag' => 'billing.'.env('APP_ENV'), ...],
],

The Fluentd side then matches app.**, audit.** etc. with different filters and outputs. Avoid using the level as a tag unless you add one channel per level.

Keep the stack for local fallback. A stack channel containing single + fluent gives you disk logs when Fluentd is down (with the caveat that the fluent handler still attempts a connection on every record). More common in production is fluent alone plus Fluentd's own buffering.

Enrich via middleware + Monolog processors, not per-call arrays. Attach a request ID / user ID once and let every record inherit it:

Log::channel('fluent')->getLogger()->pushProcessor(function ($record) {
    $record['extra']['request_id'] = app(RequestId::class)->value();
    $record['extra']['user_id']    = auth()->id();
    return $record;
});

Do this in a service provider bound to the channel, not globally, so you don't pollute other handlers.

Structured payloads. Pass arrays, not interpolated strings. The handler serializes the Monolog record (message, context, level, channel, datetime, extra) into a MessagePack map, so downstream consumers can filter on context.order_id instead of regexing text.

Lumen. No auto-discovery: in bootstrap/app.php call $app->register(\Ytake\LaravelFluent\FluentServiceProvider::class); and $app->configure('logging');, then place the channel config where Lumen can read it (usually config/logging.php copied in).

Testing. Log::fake() swaps the manager and will not exercise the custom driver. Assert on the channel's underlying Monolog logger:

$logger = Mockery::mock(\Monolog\Logger::class);
$logger->shouldReceive('info')->once()->with('order.created', Mockery::on(...));
Log::shouldReceive('channel')->with('fluent')->andReturn($logger);

Or bind a fake handler to the fluent channel in a test service provider.

Container/sidecar topology. In Docker Compose, FLUENT_HOST=fluentd (service name), not 127.0.0.1. In Kubernetes, point at the Fluent Bit daemonset's forward port or a localhost sidecar; cross-node traffic to a single Fluentd pod is a scaling bottleneck.

Gotchas and Tips

Failures are quiet. FluentLogger writes errors through an internal error handler (typically error_log), not exceptions. If Fluentd is unreachable you get a PHP warning in the web server log and the application record is simply dropped. Always test connectivity independently (fluent-cat, nc -zv host 24224) and monitor Fluentd's in_forward metrics.

PackerException on non-scalar context. The MessagePack packer only accepts scalars, arrays, and null. Passing a Throwable, model, Collection, Closure, or resource in the context array throws at log time — inside an exception handler, which is the worst place for a secondary failure. Normalize first:

'error' => [
    'class'   => get_class($e),
    'message' => $e->getMessage(),
    'file'    => $e->getFile().':'.$e->getLine(),
    'trace'   => $e->getTraceAsString(), // or array_slice($e->getTrace(), 0, 20)
],

Non-UTF-8 strings also break packing. User input, binary payloads, or Latin-1 data will fail. Run mb_convert_encoding($v, 'UTF-8', 'UTF-8') or scrub before logging.

Synchronous, per-record I/O. Each Log::… call packs and writes immediately; there is no batching in the handler. Hot loops (per-query logging, per-item import logs) will dominate request time and can fill the socket buffer. Reduce log volume, raise the handler level, or aggregate before logging.

Timeouts and blocking. The underlying FluentLogger blocks on a slow/unresponsive Fluentd until its socket timeout. Tune the connection/socket options exposed through the channel config, and never let a log call become the slowest part of a request. Fluentd restarts without a buffered forwarder are a classic source of request latency spikes.

The tag is fixed per channel. There's no per-record tag override through the standard Log::info() API. If you need audit.login vs audit.payment, you either create channels or reach into the Monolog logger and manipulate the handler — the former is far more maintainable.

level filtering is local, not in Fluentd. Setting 'level' => 'warning' drops debug/info before they hit the socket; Fluentd receives no trace of them. Conversely, if Fluentd filters later, you're paying the network cost for discarded records.

Version pinning matters — and 8.0.0 is a major bump. The 8.0.0 release notes list only "Fix tests to support Laravel 12", which usually means the runtime code is unchanged and the major bump exists to widen/narrow the support matrix (Laravel 12 ships with Monolog 3 and PHP 8.2+). Treat it as a compatibility signal, not a feature release: read the tagged composer.json before upgrading, and don't let a composer update move you from 7.x to 8.x implicitly. This package bridges Laravel's logging factory and Monolog, both of which changed interfaces in the Monolog 2 → 3 and Laravel 9 → 10 transitions, so a silent Monolog bump can still break handler registration even when the package code is identical.

Extension points. The handler and formatter are replaceable: bind your own FluentLogger instance or subclass the package handler to add batching, per-record tags, or a custom packer. Because it's registered via Log::extend, you can also re-register the fluent driver in a late-running provider to override behavior without forking — useful if you need to patch behavior faster than the release cadence.

Log volume is a cost decision. Fluentd → Elasticsearch/BigQuery bills on bytes and cardinality. Avoid dumping full request payloads, full SQL bindings, or stack traces on every record; log identifiers and summarize, and use Fluentd filters to drop noisy tags before they reach storage.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle