Logging
When error details are hidden from the visitor, the only way to learn about them is the log — a file where the application records what happened and when. Slim has no logger, but it accepts any logger that follows the PSR-3 standard. Monolog is the usual choice.
Installation
composer require monolog/monologWhere the log lives
Create a var folder in the project root and log inside it. var holds files the application creates while running: logs and cache. They are not added to the repository — put var/ into .gitignore.
The container definition
// config/container.php
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Psr\Log\LoggerInterface;
LoggerInterface::class => function () {
$logger = new Logger('app');
$logger->pushHandler(new StreamHandler(__DIR__ . '/../var/log/app.log'));
return $logger;
},The entry key is the LoggerInterface interface: classes ask for the interface in the constructor, not for a specific library. StreamHandler says the records go to the file var/log/app.log.
Writing from an action
// src/Action/CreatePostAction.php
use Psr\Log\LoggerInterface;
public function __construct(
private PostRepository $posts,
private LoggerInterface $logger,
// ... other dependencies
) {}$id = $this->posts->create(trim($data['title']), trim($data['body']));
$this->logger->info('Post created', ['id' => $id]);Create a post through the form and open var/log/app.log — it has a line with the date, the INFO level, the text and the post number. The second argument is an array of extra data.
Levels
| Method | What for |
|---|---|
debug() | Details for debugging |
info() | Ordinary events: a login, a record created |
warning() | Suspicious, but not an error |
error() | An error, the request failed |
critical() | A vital part failed: the database is down |
Errors in the log
To have the error middleware write exceptions to the same file, pass the logger as the fourth argument:
// config/middleware.php
use Psr\Log\LoggerInterface;
$logger = $app->getContainer()->get(LoggerInterface::class);
$errorMiddleware = $app->addErrorMiddleware($settings['debug'], true, true, $logger);The writing is done by Slim's standard handler. Your own handler from the previous lesson replaces it, so it must write to the log itself. Add $logger to its function through use, plus one line:
// config/middleware.php
function (ServerRequestInterface $request, Throwable $exception) use ($app, $logger) {
$status = $exception instanceof HttpException ? $exception->getCode() : 500;
if ($status >= 500) {
$logger->error($exception->getMessage(), ['exception' => $exception]);
}
// ... building the response
}404 errors do not go to the log: they are not an application failure but a wrong address.
Checking
Temporarily add the line throw new RuntimeException('Log check'); to any action, open the page and look into var/log/app.log — there is an ERROR record with that text. Then remove the line.
Common mistake
Passwords, tokens and whole form contents must not be written to the log: many people read the log file, and it is kept for a long time. Record the user or post number, not the data. And watch the file size: RotatingFileHandler can replace StreamHandler — it starts a new file every day and deletes old ones.