Installation Add the bundle via Composer:
composer require bexlardi/symfonylogbundle
Register the bundle in config/bundles.php (Symfony):
return [
// ...
Bexlardi\SymfonyLogBundle\BexlardiSymfonyLogBundle::class => ['all' => true],
];
Configuration Publish the default config:
php artisan vendor:publish --provider="Bexlardi\SymfonyLogBundle\BexlardiSymfonyLogBundle" --tag="config"
Edit config/symfony_log.php to define log channels, handlers, and formatters.
First Use Case Inject the logger into a service/controller:
use Psr\Log\LoggerInterface;
class MyController extends Controller
{
public function __construct(private LoggerInterface $logger)
{
$this->logger->info('Application started', ['context' => 'startup']);
}
}
Structured Logging Use associative arrays for context:
$this->logger->debug('User action', [
'user_id' => $user->id,
'action' => 'profile_update',
'ip' => $request->ip(),
]);
Channel-Specific Logging
Route logs to different handlers (e.g., app, security, audit):
$this->logger->channel('audit')->info('Admin action', ['user' => $user->email]);
Exception Handling Log exceptions with stack traces:
try {
// Risky operation
} catch (\Exception $e) {
$this->logger->error('Operation failed', [
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
}
Monolog Integration
Extend Monolog handlers (e.g., StreamHandler, FingersCrossedHandler):
$this->logger->pushHandler(new \Monolog\Handler\StreamHandler(
storage_path('logs/custom.log'),
\Monolog\Logger::DEBUG
));
Middleware for Request Logging Log HTTP requests/responses in middleware:
public function handle($request, Closure $next)
{
$this->logger->info('Incoming request', [
'method' => $request->method(),
'path' => $request->path(),
'ip' => $request->ip(),
]);
$response = $next($request);
$this->logger->info('Request completed', [
'status' => $response->getStatusCode(),
]);
return $response;
}
Event-Based Logging Log critical events via Symfony’s event dispatcher:
$dispatcher->addListener('user.registered', function ($event) {
$this->logger->info('User registered', [
'email' => $event->getUser()->getEmail(),
]);
});
Channel Mismatch
config/symfony_log.php match those used in code.$this->logger->getHandlers(); // Check active handlers
Performance Overhead
debug() or verbose() for development; info()/warning() for production.Log Rotation
max_files and file_permission in handlers to prevent disk issues:
'handlers' => [
'main' => [
'type' => 'stream',
'path' => '%kernel.logs_dir%/%kernel.environment%.log',
'level' => 'debug',
'max_files' => 30, // Rotate after 30 files
],
],
Sensitive Data
masking in context:
$this->logger->info('Login attempt', [
'email' => $user->email,
'password' => '********', // Manually mask
]);
Symfony vs. Laravel Quirks
autowire: true in services.yaml for Laravel compatibility:
services:
App\Services\MyService:
arguments:
$logger: '@logger'
ContainerInterface. For Laravel, bind the logger manually:
$this->app->bind('logger', function () {
return new \Monolog\Logger('app', $this->app['monolog.handler']);
});
Check Log Levels
debug > info > notice > warning > error > critical > alert > emergency.'handlers' => [
'main' => ['level' => 'debug'], // Log everything
],
Handler-Specific Issues
path is writable (chmod -R 775 storage/logs).action_level is set to bubble up critical logs.Log Formatting
'formatters' => [
'custom' => [
'format' => '%datetime% | %level_name% | %message% %context% %extra%',
],
],
Laravel-Specific Fixes
Log facade, alias the bundle’s logger:
Log::shouldUseDailyFiles(); // Use Laravel’s default
Log::info('Test', ['logger' => 'SymfonyLogBundle']);
Custom Handlers
Extend Bexlardi\SymfonyLogBundle\Handler\AbstractHandler for bespoke logging (e.g., Slack, Datadog).
Processor Integration Add Monolog processors for data enrichment:
$processor = new \Monolog\Processor\UidProcessor();
$this->logger->pushProcessor($processor);
Dynamic Channels Create channels programmatically:
$channel = $this->logger->channel('dynamic_channel');
$channel->info('Dynamic log');
Log Enrichment Use middleware to add metadata (e.g., user ID, request ID):
$this->logger->pushProcessor(function (array $record) {
$record['extra']['request_id'] = $this->getRequestId();
return $record;
});
How can I help you explore Laravel packages today?