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 Log Enhancer Laravel Package

freshbitsweb/laravel-log-enhancer

Laravel Log Enhancer automatically enriches every log entry with useful request context—logged-in user ID, request URL, IP address, input and session data—so you can debug production issues faster. Quick to install and configure, no code changes needed.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install and publish

composer require freshbitsweb/laravel-log-enhancer
php artisan vendor:publish --provider="Freshbitsweb\LaravelLogEnhancer\LaravelLogEnhancerServiceProvider"

The service provider is auto-discovered on Laravel 5.6+, so there is nothing to register in config/app.php. The publish step drops config/log-enhancer.php into your app — that file is the real documentation for this package. Read it before anything else, then read the two source files behind it (src/LaravelLogEnhancerServiceProvider.php and the processor class it registers) so you know exactly where in the Monolog pipeline the extra context is injected.

2. Verify it works before configuring it

Don't start by editing config. Prove the wiring first:

php artisan tinker
>>> Log::info('log-enhancer probe', ['order_id' => 42]);

Then inspect the tail of the channel you actually use:

tail -n 5 storage/logs/laravel.log
# or, if you log JSON:
tail -n 5 storage/logs/laravel.log | jq '.context'

You should see your own order_id context plus the package's extra keys (typically a user block, a request block with method/URL/input, and possibly session/runtime info — the exact keys depend on the published config). If you see only order_id, the processor isn't attached to that channel; jump to the Gotchas section.

3. First real use case

The highest-value first use is reproducing a customer-reported error. In staging, take a failing request, hit it, and read the log entry: the package should tell you who was logged in, what URL/method was called, and what payload came in — without you having to add temporary Log::info() calls. That round-trip (report → log line → reproduce) is the entire reason to install this.

Start with a deliberately narrow config: enable user details, enable request method + URL, and leave request input disabled until you've decided what's safe to capture.

Implementation Patterns

Environment-tiered verbosity

Treat the enhancer as a debug tool, not a production audit trail. A common split:

Environment User URL/Method Input Headers Session
local ✅ ✅ ✅ (whitelisted) ❌ ❌
staging ✅ ✅ ✅ (whitelisted) ❌ ❌
production ✅ (ID only) ✅ ❌ ❌ ❌

Drive this from env vars in config/log-enhancer.php so it survives config:cache, rather than editing the file per environment. In production, reduce user fields to ['id'] — an identifier is enough to join against your DB, and you avoid shipping emails/names into a text file with 30-day retention.

Give the logger a correlation ID

The enhancer tells you who and what; it doesn't tell you which of the five concurrent requests a line belongs to. Pair it with a middleware that stamps a request ID:

// app/Http/Middleware/RequestId.php
public function handle($request, Closure $next)
{
    $id = $request->header('X-Request-Id') ?: (string) Str::uuid();
    Log::withContext(['request_id' => $id]);

    $response = $next($request);
    return $response->header('X-Request-Id', $id);
}

Laravel 8+'s Log::withContext() merges into every record's context array, so it sits alongside the enhancer's data instead of fighting it. Now grep request_id across the whole request lifecycle — including queued work dispatched from it if you propagate the ID into the job payload.

Whitelist input, never blacklist

If you enable request input, do it as an allowlist of fields you actually debug with:

'request' => [
    'include' => ['url', 'method', 'input'],
    'input'   => [
        'only' => ['email', 'plan_id', 'coupon_code', 'step'],
    ],
],

(Key names are indicative — check your published file.) Blacklisting password and password_confirmation is a losing game the moment someone adds token, api_key, card_number, or secret_answer. An allowlist fails closed.

Handle queue/CLI context explicitly

In Artisan commands and queued jobs there is no HTTP request and usually no authenticated user, so the enhancer's request block will be empty or absent. Don't rely on it there. Instead, push job context manually at the top of handle():

public function handle()
{
    Log::withContext([
        'job'      => static::class,
        'job_id'   => $this->job?->getJobId(),
        'tenant_id'=> $this->tenantId,
    ]);
    // ...
}

This is the single biggest gap between "log line is useful" and "log line says user: null, url: null" when you're debugging a failed job at 2am.

Channel strategy

Keep the enhancer off your noisy channels. If you ship logs to an external aggregator with its own context enrichment, or you have a high-frequency audit channel, define a separate Laravel channel for it that doesn't get the processor, and keep the enhancer on daily/single only. Conversely, in containers, point it at stderr so the orchestrator captures it — the enhancer is channel-agnostic as long as the channel is created by the LogManager.

Gotchas and Tips

Secrets will end up on disk. This is the number-one risk. A login failure log line with the full request body gives you plaintext passwords in storage/logs/laravel.log, which is frequently world-readable on shared hosts and gets shipped to third parties. Audit your config and audit the $hidden/$fillable situation on anything you log. If the package serialises models, remember $hidden is respected by toArray() but not by (array) $model or dd()-style dumps.

Large payloads are a performance and disk problem. Base64 images, JSON blobs, and bulk-array endpoints blow up log size fast. A 2 MB request body serialised into every log line in that request is a real latency regression on busy endpoints. Cap or skip: exclude known-large fields, or disable input logging on upload endpoints.

Auth resolution timing matters. Logging before the auth middleware runs yields user: null. More commonly, multi-guard apps get this wrong: if your API uses auth:sanctum or auth:api, but the config says 'guard' => 'web', the processor resolves the web guard (empty session) and you get null users in exactly the logs you care about. Set the guard per environment, or check whether the package resolves the authenticated guard by default.

CLI and queue noise. Expect url: null / method: null / user: null on every console line. If that's cluttering logs, either add a separate console-friendly channel or accept it — but know that its presence is not a bug.

Octane / long-running workers. Verify compatibility explicitly: a processor that resolves user/request state at registration time will leak one request's data into the next under Octane or Swoole. The correct implementation resolves per-record. Run two different authenticated requests under Octane and confirm the log lines don't cross-contaminate — this is cheap to test and catastrophic to miss.

Duplicate or clobbered context. With LOG_CHANNEL=stack, each nested channel builds its own logger. If a processor is registered both globally and per-channel, you'll see duplicated keys; if another tap or processor writes the same key, last-writer-wins silently. If you're on Laravel 8+, Log::withContext() and the package may both write into context — confirm merge order with a probe.

Tests break on exact assertions. Any test doing Log::shouldReceive('error')->with('msg') still works, but snapshot/string-match assertions on log output will now include extra keys. Prefer Log::spy() + argument-level assertions over substring matching. Also remember to actingAs($user) in tests if you want to exercise the user block.

config:cache ordering. If you drive config from env(), run php artisan config:cache after setting the env vars in that environment. Stale cached config is the most common cause of "I enabled it but nothing changed."

Version drift. The package targets Laravel 5.6+; Laravel 10/11 moved to Monolog 3, where processor interfaces and record shape changed. Confirm the release you install declares support for your Laravel/Monolog pairing (composer why monolog/monolog) before rolling it out, especially if you're on an older Laravel that's stuck on Monolog 1/2.

Extension points. If the built-in context isn't enough (tenant ID, feature flags, deployment SHA), don't fork — register your own Monolog processor via a channel's tap option, or wrap it in a middleware with Log::withContext(). Reserve the package's own config for user/request/session data and keep your custom dims separate; that keeps upgrades clean.

PII and retention. Enhanced logs are PII-dense. Set LOG_DAILY_DAYS to something defensible, make sure the error-tracking vendor you forward to has a matching retention policy, and check whether the log path is exposed by a misconfigured web server. This package makes debugging better and compliance slightly worse — budget for both.

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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager