Installation Add the bundle via Composer:
composer require symfony/monolog-bundle
Register the bundle in config/bundles.php (Symfony) or config/app.php (Laravel via Symfony integration):
return [
// ...
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
];
Basic Configuration
Configure handlers in config/packages/monolog.yaml (Symfony) or config/monolog.php (Laravel):
monolog:
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
First Use Case Log a message in a controller or service:
use Psr\Log\LoggerInterface;
class ExampleController extends AbstractController
{
public function index(LoggerInterface $logger)
{
$logger->info('User accessed the homepage');
return new Response('Logged!');
}
}
Type-Hint LoggerInterface in constructors/services to leverage dependency injection:
public function __construct(private LoggerInterface $logger) {}
Named Loggers (Symfony-specific):
monolog:
channels: [auth, security]
Inject by name:
public function __construct(LoggerInterface $logger, LoggerInterface $authLogger) {}
Add Context for structured logs:
$logger->info('Order processed', [
'order_id' => $order->id,
'user_id' => $order->user_id,
'amount' => $order->amount,
]);
Bags for Grouped Context:
$logger->withContext(['user_id' => 123])->info('Event triggered');
Dynamic Handlers (e.g., Slack, Sentry):
handlers:
slack:
type: slack
token: "%env(SLACK_TOKEN)%"
channel: "#logs"
level: error
formatter: monolog.formatter.json
Channel-Specific Handlers:
handlers:
security:
type: stream
path: "%kernel.logs_dir%/security.log"
level: warning
channels: [security]
Psr\Log\LoggerInterface in Laravel services:
public function __construct(private LoggerInterface $logger) {}
config/monolog.php:
return [
'handlers' => [
'single' => [
'type' => 'stream',
'path' => storage_path('logs/laravel.log'),
'level' => 'debug',
],
],
];
public function handle($request, Closure $next)
{
$logger->info('Incoming request', [
'method' => $request->method(),
'path' => $request->path(),
]);
$response = $next($request);
$logger->info('Outgoing response', [
'status' => $response->getStatusCode(),
]);
return $response;
}
Level Overrides
level to avoid unexpected filtering:
handlers:
nested:
type: group
members: [stream1, stream2]
level: debug # Override for all members
Circular References in Context
__debugInfo() or manually extract data:
$logger->info('User data', $user->toArray());
Performance with High-Volume Logs
null formatter for high-throughput logs to skip serialization:
handlers:
high_volume:
type: stream
path: "%kernel.logs_dir%/high_volume.log"
level: info
formatter: null
Symfony vs. Laravel Paths
storage_path() differs from Symfony’s %kernel.logs_dir%. Use:
path: "%kernel.project_dir%/storage/logs/app.log"
Check Log Levels
$logger->debug('This should appear if level is debug');
$logger->alert('This should always appear');
Formatter Issues
monolog.formatter.json vs. monolog.formatter.line).Handler Activation
level: debug temporarily to confirm handlers are active:
handlers:
test:
type: stream
path: "%kernel.logs_dir%/test.log"
level: debug
Custom Handlers
Monolog\Handler\AbstractProcessingHandler:
class MyHandler extends AbstractProcessingHandler
{
protected function write(array $record): void
{
// Custom logic (e.g., send to external API)
}
}
handlers:
my_handler:
type: my_handler
level: info
Processors
processors:
id: [Symfony\Component\Monolog\Processor\UidProcessor]
class RequestIdProcessor extends Processor
{
public function __invoke(array $record): array
{
$record['extra']['request_id'] = request()->header('X-Request-ID');
return $record;
}
}
Dynamic Handler Configuration
handlers:
error_monitor:
type: monitor
level: error
enabled: "%env(bool:MONITOR_ERRORS)%"
Laravel’s Default Logger
AppServiceProvider:
// Avoid this if using MonologBundle
$this->app['log'] = Log::class;
Queue Logs
async handler:
handlers:
async:
type: async
handler: buffered
level: debug
Log Channels
single, stack) map to Monolog handlers. Configure in config/logging.php:
'channels' => [
'monolog' => [
'driver' => 'monolog',
'level' => 'debug',
'handler' => 'main', // Matches monolog.yaml
],
],
How can I help you explore Laravel packages today?