Observability

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.

example.php
$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().

example.php
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.

example.php
final class ImportService
{
    public function __construct(
        private readonly LoggerInterface $logger,
    ) {
    }

    public function run(): void
    {
        $this->logger->info('Import started');
    }
}