Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

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/monolog

Where 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

MethodWhat 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.

Thanks for reading!

Donate to the site — we work hard for you.