Logging
Logging channels, PSR logger bindings, log file path convention and practical usage patterns.
Provider wiring
LoggingServiceProvider registers LogFilePathResolver, LogManager, alias log, alias log.app, alias log.benchmark and maps Psr\Log\LoggerInterface to log.app. The provider also sets the container diagnostic logger to the app logger channel.
$container->singleton(LogFilePathResolver::class, LogFilePathResolver::class);
$container->singleton(LogManager::class, LogManager::class);
$container->singleton('log', LogManager::class);
$container->singleton('log.app', static function (ContainerInterface $container): LoggerInterface {
$manager = $container->get(LogManager::class);
$logger = $manager->app();
$container->setDiagnosticLogger($logger);
return $logger;
});
$container->singleton('log.benchmark', static fn (ContainerInterface $container): LoggerInterface => $container->get(LogManager::class)->benchmark());
$container->singleton(LoggerInterface::class, static fn (ContainerInterface $container): LoggerInterface => $container->get('log.app'));
Configuration
Logging channels are configured in app/Config/Logging.yaml. YAML is the app-level source format only; the framework maps it into typed LoggingConfigDefinition and resolves runtime LoggingConfig. Channel methods on LogManager are app(), error(), request() and benchmark().
module: logging
config:
app:
enabled: true
path: app.log
days: 7
error:
enabled: true
not_found: false
path: error.log
days: 7
request:
enabled: false
path: request.log
days: 7
min_status: 0
benchmark:
enabled: true
path: benchmark.log
days: 7
Log file path convention
Log filenames are resolved through LogFilePathResolver. Relative filenames such as app.log are stored under storage/writable/logs. Absolute paths are preserved.
Framework internal logging
Kernel and CLI failures are logged via ExceptionLogger. Container diagnostics also use the logger configured by LoggingServiceProvider through the container diagnostic logger binding.
Channel behavior
Disabled channels resolve to Psr\Log\NullLogger, so application code can log safely without per-call channel availability checks.
Usage through dependency injection
Prefer constructor injection of Psr\Log\LoggerInterface for application services. Use LogManager only when explicit channel selection is required.
final class ImportService
{
public function __construct(
private readonly LoggerInterface $logger,
) {
}
public function run(): void
{
$this->logger->info('Import started');
}
}