Logging Service Provider
Logger channels, PSR logger bindings and writable log file path resolution.
Responsibility
Registers framework logging infrastructure: LogFilePathResolver, LogManager, alias log, alias log.app, default Psr\Log\LoggerInterface binding and alias log.benchmark. Channel creation and disabled-channel fallback are owned by LogManager.
Bindings
LoggerInterface resolves to the app logger channel via alias log.app. Alias log resolves to LogManager. Alias log.benchmark resolves directly to the benchmark logger. There are no log.error or log.request aliases; use LogManager for those channels.
use Lemonade\Framework\Core\Logging\LogManager;
use Psr\Log\LoggerInterface;
$logger = $container->get(Psr\Log\LoggerInterface::class);
$appLogger = $container->get('log.app');
$benchmarkLogger = $container->get('log.benchmark');
$logs = $container->get(LogManager::class);
$errorLogger = $logs->error();
$requestLogger = $logs->request();
Logger channels
LogManager exposes four framework channels: app(), error(), request() and benchmark(). Disabled channels return Psr\Log\NullLogger, so callers can log safely without checking channel state.
$logs = $container->get(Lemonade\Framework\Core\Logging\LogManager::class);
$logs->app()->info('Application message');
$logs->error()->error('Error message');
$logs->request()->info('Request message');
$logs->benchmark()->info('Benchmark message');
Log file path convention
Log file config values are resolved through ApplicationContext::resolveLogPath(). Relative filenames are stored under the framework writable log directory, conventionally storage/writable/logs; absolute paths are preserved by the context path resolver.
$resolver = $container->get(Lemonade\Framework\Core\Logging\LogFilePathResolver::class);
$path = $resolver->resolve('app.log', 'app.log');
Configuration
LogManager reads {channel}.log.enabled, {channel}.log.file and {channel}.log.days for each channel. App config may source these values from environment variables, but the framework contract is the config structure, not the env var names.
'app' => [
'log' => [
'enabled' => true,
'file' => 'app.log',
'days' => 7,
],
],
'error' => [
'log' => [
'enabled' => true,
'not_found' => false,
'file' => 'error.log',
'days' => 7,
],
],
'request' => [
'log' => [
'enabled' => false,
'file' => 'request.log',
'days' => 7,
'min_status' => 0,
],
],
'benchmark' => [
'log' => [
'enabled' => false,
'file' => 'benchmark.log',
'days' => 7,
],
],
Rotation format
RotatingFileLogger writes JSON lines to dated files. A configured app.log writes records to files like app-YYYY-MM-DD.log; old files matching the channel filename pattern are removed according to {channel}.log.days.
HTTP boundary
LoggingServiceProvider registers loggers and channels only. HTTP request logging is performed by RequestLoggingMiddleware, which uses LogManager::request() and request.log.min_status. Benchmark logging is performed by BenchmarkMiddleware, which uses LogManager::benchmark() when benchmark.log.enabled is true.
Benchmark channel
Benchmark logging can be resolved through alias log.benchmark or LogManager::benchmark(). The benchmark channel can be disabled independently from the main application logger.
$benchmark = $container->get('log.benchmark');
$benchmark->info('Benchmark finished', [
'duration_ms' => 12.4,
]);
Provider boundary
LoggingServiceProvider does not define application log messages, route logging policy or benchmark collection. It only supplies PSR-compatible logger services; middleware and application code decide what to log.