Log
Foundation Log configures Monolog behind the standard Psr\Log\LoggerInterface. Application services depend on the PSR-3 contract, while configuration selects where records are written and which levels are kept.
Installation
Section titled “Installation”Install the split package:
Prepare the application
Section titled “Prepare the application”Foundation Log uses the shared application configuration and provider architecture established in these guides:
Configuration
Section titled “Configuration”Choose where records are written
Section titled “Choose where records are written”Set one channel for the application:
| Channel | Writes to | Use when |
|---|---|---|
console |
A configured stream, with colored levels | Local development, CLI processes, or container logs |
errorlog |
PHP’s error_log() |
The hosting platform collects the PHP error log |
stack |
The selected channels; defaults to console and errorlog |
Records should reach several destinations |
null |
Nothing | Logging must be intentionally disabled, including in focused tests |
Map the channel, minimum level, and stream in the application’s root config.php:
The stream setting is used by console and by the console side of stack. Common values are php://stdout and php://stderr.
Combine channels and add a custom handler
Section titled “Combine channels and add a custom handler”Set log.channels.stack.channels to the channel names you want to combine. The list replaces the supplied console and errorlog selection. Add a named channel with a handler class to include your own Monolog handler.
In the application’s root config.php, this example selects console, PHP error log, and an existing application Audit_Handler:
Foundation supplies the built-in channel definitions; configure only the settings you want to change. You can also define another stack name with its own channels list, or select audit directly with APP_LOG_CHANNEL=audit. Application services continue injecting LoggerInterface.
Custom handlers implement Monolog’s HandlerInterface. Foundation resolves them through the container, so their dependencies use ordinary application provider bindings. An optional formatter class selects a formatter for handlers implementing FormattableHandlerInterface; setting it to null keeps the handler’s own formatter. Handlers extending Monolog’s AbstractHandler receive log.level; implementations of the minimal HandlerInterface own their filtering behavior.
List handler-backed channels as stack members. Handlers run in reverse list order, preserving Monolog’s pushHandler() behavior; a handler with bubbling disabled stops delivery to earlier entries. An empty stack, or one whose only handler is an unavailable PHP error log, discards records.
Choose the minimum level
Section titled “Choose the minimum level”The configured level keeps records at that severity and above:
| Level | Typical use |
|---|---|
debug |
Detailed diagnostics useful during development |
info |
Normal application milestones |
notice |
Significant but expected events |
warning |
Unexpected conditions from which the operation can recover |
error |
An operation failed but the application can continue |
critical |
A major application capability is unavailable |
alert |
Immediate operator action is required |
emergency |
The application or site is unusable |
Use lowercase names in configuration. Foundation also accepts title case and uppercase variants.
Register the logging provider
Section titled “Register the logging provider”In src/App.php, add LogProvider before feature providers that consume LoggerInterface:
LogProvider is an optional default. Applications can configure additional Monolog handlers through named channels, or supply a complete replacement by binding LoggerInterface in their own provider.
The configured application logger is a singleton. Handlers or processors added after resolution remain attached for the lifetime of that application container. A replacement application logger should normally be registered as a singleton as well; use a separate factory only when the feature intentionally needs independent logger instances.
Understand configuration failures
Section titled “Understand configuration failures”An unavailable PHP error_log() function does not stop the application:
- The
errorlogchannel falls back to the null handler. - The
stackchannel keeps the console handler and skips the unavailable error-log handler.
Invalid configuration is different. An unsupported level fails while LogProvider is registered, and an unsupported channel fails when LoggerInterface is first resolved. Use one of the documented values rather than silently losing records because of a typo.
A stack member must name a configured handler-backed channel. An unknown member or one without a handler raises ContainerException when the logger resolves; correct the channel definition before retrying.
Inject the PSR-3 logger
Section titled “Inject the PSR-3 logger”In src/Catalog/Catalog_Importer.php, depend on Psr\Log\LoggerInterface, not Monolog or a Foundation handler. Include structured context with identifiers and values needed to investigate the event:
Context remains machine-readable and keeps operational data out of the message text. Do not include passwords, access tokens, payment details, or other secrets.
Record exceptions with their context
Section titled “Record exceptions with their context”Pass the exception under the conventional exception key so handlers and processors can inspect it:
Log the failure at the boundary responsible for handling or reporting it. Avoid recording the same exception again at every layer through which it passes.
Testing
Section titled “Testing”Disable records when logging is irrelevant
Section titled “Disable records when logging is irrelevant”Replace the application logger with the PSR-3 NullLogger when a focused test does not assert logging behavior:
Assert important records
Section titled “Assert important records”Monolog’s TestHandler captures records without writing them to an external destination:
Assert logs only when they are part of the feature’s observable operational contract. Otherwise, test the feature’s result and use NullLogger.
Upgrading to 2.0
Section titled “Upgrading to 2.0”The configured LoggerInterface is now an application-lifetime singleton. Handlers or processors added to the resolved logger remain visible to later consumers of that logger. Register an explicit factory under an application-owned identifier when independent logger instances are required.
LogProvider container identifiers and channel maps are internal implementation details in 2.0. Replace references to LogProvider::LOG_LEVEL, LogProvider::CHANNEL_ERRORLOG, or LogProvider::CHANNELS with the documented log.level, log.channel, and log.channels configuration keys.