Skip to content

Monolog

ObservabilityLoggingPHP

What it is

Monolog is PHP's standard logging library, implementing PSR-3 with handlers for files, syslog, Slack, Sentry, Elasticsearch and dozens more.

A Logger has a stack of handlers, each with a minimum level. Processors enrich every record with extra context.

Installation

composer require monolog/monolog

Getting started

The smallest useful thing you can do with it, and what each part means.

Handlers, levels and context
<?php
use Monolog\{Logger, Level};
use Monolog\Handler\{StreamHandler, RotatingFileHandler};
use Monolog\Formatter\JsonFormatter;

$log = new Logger('app');

$file = new RotatingFileHandler(__DIR__ . '/logs/app.log', 14, Level::Info);
$file->setFormatter(new JsonFormatter());
$log->pushHandler($file);

$log->pushHandler(new StreamHandler('php://stderr', Level::Error));

// The second argument is structured context, not interpolation.
$log->info('Order shipped', [
    'order_id' => $order->id,
    'customer' => $order->customer,
    'total'    => $order->total,
]);
Passing values as context rather than concatenating them into the message is what makes logs queryable — the JSON formatter turns each key into an indexed field.

Advanced usage

Where the library earns its place over a simpler alternative.

Processors and fingers-crossed handling
<?php
// Stamp every record with request context.
$log->pushProcessor(function (Monolog\LogRecord $record) {
    $record->extra['request_id'] = RequestContext::id();
    $record->extra['memory'] = memory_get_usage(true);
    return $record;
});

// Buffer everything, but only write it if an error occurs — full debug
// context for failures, silence for successful requests.
$log->pushHandler(new Monolog\Handler\FingersCrossedHandler(
    new RotatingFileHandler('logs/app.log'),
    activationStrategy: Level::Error,
    bufferSize: 200,
));
FingersCrossedHandler is Monolog's best idea: you get verbose debug logs for the requests that failed, and almost no log volume for the ones that did not.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

No log output
No handler is registered, or every handler's minimum level is above the records being logged.
Log files grow without bound
Use RotatingFileHandler with a retention count, or configure logrotate.

Best practices

  • Pass data in the context array rather than interpolating it into the message.
  • Use FingersCrossedHandler in production for full context on failures without the volume.
  • Never log passwords, tokens or full request bodies.
  • Type-hint Psr\Log\LoggerInterface in your classes, not the Monolog Logger.

Background

Why it exists, and what it was reacting to.

Monolog is the logging backend behind Laravel and Symfony. Its handler and processor architecture means routing logs to a new destination is a configuration change, not a code change.