Installation Add the package via Composer:
composer require alxishin/logs-bundle
Enable the bundle in config/bundles.php:
return [
// ...
Alxishin\LogsBundle\LogsBundle::class => ['all' => true],
];
Configuration Publish the default config:
php artisan vendor:publish --tag=logs-bundle-config
Edit config/logs-bundle.php to define channels, handlers, and formatters (e.g., log_formatter).
Merge with your existing config/monolog.php (if present) to avoid conflicts.
First Use Case
Log a test message to the mailer channel (as shown in the example):
use Psr\Log\LoggerInterface;
public function testLogging(LoggerInterface $logger)
{
$logger->channel('mailer')->debug('Test mailer log message');
}
Verify logs appear in var/log/mailer.prod.log (or console in dev).
Use Channels for Isolation
Define logical channels (e.g., mailer, api, jobs) in config/logs-bundle.php:
channels:
mailer:
level: debug
handlers: [mailer]
api:
level: info
handlers: [api_handler]
Inject the logger with channel awareness:
$logger->channel('api')->info('API request received');
Dynamic Channel Switching
Override channels per environment (e.g., disable event logs in dev):
when@dev:
monolog:
handlers:
console:
channels: ['!event', '!doctrine']
Rotating Files Configure per-environment log rotation (e.g., 10 files in dev, 40 in prod):
handlers:
main:
type: rotating_file
max_files: 10 # Dev
path: '%kernel.logs_dir%/app.log'
when@prod:
handlers:
main:
max_files: 40 # Prod
Conditional Handlers
Use when@prod/when@dev to toggle handlers (e.g., disable console in prod):
when@prod:
monolog:
handlers:
console: ~ # Disabled
Custom Formatters
Extend the default log_formatter (e.g., add request IDs):
// src/Formatter/ExtendedFormatter.php
use Monolog\Formatter\LineFormatter;
class ExtendedFormatter extends LineFormatter {
public function __construct() {
parent::__construct("[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n");
}
}
Register in config:
formatters:
log_formatter:
class: App\Formatter\ExtendedFormatter
Contextual Logging
Attach metadata (e.g., user IDs, request IDs) via context:
$logger->channel('api')->info('User action', [
'user_id' => auth()->id(),
'request_id' => request()->header('X-Request-ID'),
]);
Service Binding
Bind the logger service in config/services.php:
'logger' => \Monolog\Logger::class,
Inject via constructor:
public function __construct(private LoggerInterface $logger) {}
Contextual Loggers Create scoped loggers for services:
$mailerLogger = $logger->withName('mailer');
$mailerLogger->debug('Sending email to ' . $user->email);
Merge Conflicts Avoid duplicate handlers by merging configs explicitly:
# config/packages/monolog.yaml
imports:
- { resource: logs-bundle.php }
monolog:
handlers:
nested: ~ # Override or extend
Environment Overrides
Ensure when@prod/when@dev blocks are placed after base config to avoid precedence issues.
Formatter Inheritance
If extending log_formatter, ensure the parent class is autoloaded or manually registered.
Log Level Debugging
Temporarily set level: debug for a channel to inspect all logs:
channels:
mailer:
level: debug # Temporarily enable
Handler Validation
Use php artisan logs-bundle:validate (if available) to check config syntax.
Log Rotation Gaps If logs disappear unexpectedly, verify:
max_files isn’t too low.var/log/ (e.g., chmod -R 775 var/log).Avoid Over-Logging
Use level: warning or higher for production channels to reduce I/O:
when@prod:
monolog:
handlers:
main:
level: warning
Batch Context Data For heavy contexts (e.g., SQL queries), log selectively:
$logger->channel('db')->info('Query executed', [
'query' => $sql,
'duration_ms' => $duration,
// Omit large result sets
]);
Custom Handlers Create a handler for external services (e.g., Sentry, Datadog):
// src/Handler/SentryHandler.php
use Monolog\Handler\AbstractProcessingHandler;
class SentryHandler extends AbstractProcessingHandler {
public function __construct() {
parent::__construct(Sentry::getLevel());
}
protected function write(array $record): void {
Sentry::captureMessage($record['message'], $record['level']);
}
}
Register in config:
handlers:
sentry:
type: sentry
level: error
Log Enrichment Use middleware to add request context:
// app/Http/Middleware/AddRequestId.php
public function handle($request, Closure $next) {
$logger = app(LoggerInterface::class);
$logger->withName('http')->info('Request started', [
'method' => $request->method(),
'path' => $request->path(),
'ip' => $request->ip(),
]);
return $next($request);
}
Log Export Stream logs to external systems via handlers (e.g., Syslog, HTTP):
handlers:
syslog:
type: syslog
identifier: 'laravel_app'
level: debug
How can I help you explore Laravel packages today?