Monolog es la librerÃa de logging más popular en el ecosistema PHP. Implementa PSR-3 (LoggerInterface) y funciona mediante un sistema de capas: cada Logger tiene uno o varios Handlers que deciden dónde escribir los mensajes; los Processors añaden contexto automático a cada registro; y los Formatters determinan el formato de salida (texto, JSONÂ…).
Instalación y logger básico
composer require monolog/monolog
<?php
use MonologLogger;
use MonologHandlerStreamHandler;
use MonologLevel;
// Crear un logger con nombre de canal
$log = new Logger('mi-app');
// Añadir un handler: escribe en fichero a partir del nivel WARNING
$log->pushHandler(new StreamHandler('/var/log/mi-app/app.log', Level::Warning));
// Añadir otro handler: escribe en stdout a partir del nivel DEBUG
$log->pushHandler(new StreamHandler('php://stdout', Level::Debug));
// Usar los 8 niveles PSR-3
$log->debug('Variable en memoria', ['valor' => 42]);
$log->info('Usuario autenticado', ['id' => 123]);
$log->warning('Espacio en disco bajo', ['libre_gb' => 1.2]);
$log->error('Fallo al enviar email', ['destinatario' => '[email protected]']);
$log->critical('Base de datos no disponible');
Apilar handlers
Monolog procesa los handlers en pila (el último añadido se ejecuta primero). Puedes combinar tantos como necesites:
<?php
use MonologHandlerStreamHandler;
use MonologHandlerRotatingFileHandler;
use MonologHandlerSyslogHandler;
use MonologHandlerSlackWebhookHandler;
use MonologLevel;
$log = new Logger('produccion');
// Fichero con rotación diaria, máx 30 dÃas de histórico
$log->pushHandler(
new RotatingFileHandler('/var/log/app/app.log', 30, Level::Debug)
);
// Syslog para integración con la pila de logs del sistema
$log->pushHandler(new SyslogHandler('mi-app', LOG_USER, Level::Notice));
// Slack para errores crÃticos (webhook URL en variable de entorno)
$log->pushHandler(
new SlackWebhookHandler(
webhookUrl: getenv('SLACK_WEBHOOK'),
channel: '#alertas-prod',
username: 'MonologBot',
useAttachment: true,
iconEmoji: ':fire:',
level: Level::Critical
)
);
Processors: contexto automático
Un Processor es un callable que recibe el array del registro y devuelve el array modificado. Úsalos para añadir automáticamente IP, ID de petición, usuario en sesión, etc. sin tener que hacerlo manualmente en cada llamada:
<?php
use MonologProcessorIntrospectionProcessor;
use MonologProcessorWebProcessor;
use MonologProcessorMemoryUsageProcessor;
$log = new Logger('api');
// Añade fichero y lÃnea donde se llamó al logger
$log->pushProcessor(new IntrospectionProcessor());
// Añade URL, IP, método HTTP, usuario-agente
$log->pushProcessor(new WebProcessor());
// Añade uso de memoria en cada registro
$log->pushProcessor(new MemoryUsageProcessor());
// Processor personalizado: añadir el ID de la petición
$requestId = bin2hex(random_bytes(8));
$log->pushProcessor(function (array $record) use ($requestId): array {
$record['extra']['request_id'] = $requestId;
return $record;
});
$log->info('Petición recibida');
// Incluye: fichero, lÃnea, URL, IP, método, request_id, memoria
Formatters: texto o JSON
<?php
use MonologFormatterLineFormatter;
use MonologFormatterJsonFormatter;
use MonologHandlerStreamHandler;
// Formato de lÃnea personalizado
$handler = new StreamHandler('/var/log/app/app.log', Level::Debug);
$formatter = new LineFormatter(
format: "[%datetime%] %channel%.%level_name%: %message% %context% %extra%n",
dateFormat: 'Y-m-d H:i:s.u',
allowInlineLineBreaks: true,
ignoreEmptyContextAndExtra: true,
);
$handler->setFormatter($formatter);
// Formato JSON (útil para ELK Stack, Grafana Loki, Datadog…)
$jsonHandler = new StreamHandler('php://stdout', Level::Debug);
$jsonHandler->setFormatter(new JsonFormatter());
$log = new Logger('app');
$log->pushHandler($handler);
$log->pushHandler($jsonHandler);
Múltiples canales de log
En proyectos grandes es útil tener un logger por canal (base de datos, emails, pagos…) para poder filtrar y analizar los logs por subsistema:
<?php
use MonologLogger;
use MonologHandlerRotatingFileHandler;
use MonologLevel;
function crearLogger(string $canal, string $fichero): Logger {
$log = new Logger($canal);
$log->pushHandler(new RotatingFileHandler($fichero, 30, Level::Debug));
return $log;
}
$logBd = crearLogger('bd', '/var/log/app/bd.log');
$logEmail = crearLogger('email', '/var/log/app/email.log');
$logPagos = crearLogger('pagos', '/var/log/app/pagos.log');
$logSeguridad = crearLogger('seguridad', '/var/log/app/seguridad.log');
$logPagos->info('Pago recibido', ['importe' => 99.99, 'usuario_id' => 42]);
$logSeguridad->warning('Intento de acceso fallido', ['ip' => '1.2.3.4']);
Integración con frameworks
- Laravel: Monolog es el backend de logging por defecto; se configura en
config/logging.php. - Symfony: usa el componente Monolog Bundle; los canales se definen en
config/packages/monolog.yaml. - Slim, Mezzio y otros: se registra Monolog en el contenedor DI como
LoggerInterface.
