<h2>Por que Logging Profissional Importa</h2>
<p>Logging é frequentemente negligenciado por desenvolvedores iniciantes, mas é a diferença entre um código que funciona e um código que você consegue manter em produção. Quando algo falha em produção, os logs são sua única fonte de verdade. O Monolog é a biblioteca padrão da comunidade PHP para logging, utilizada por frameworks como Laravel, Symfony e inúmeros projetos de grande escala. Dominá-la significa escrever aplicações profissionais que são fáceis de debugar, monitorar e manter.</p>
<h2>Entendendo a Arquitetura do Monolog</h2>
<h3>Componentes Principais</h3>
<p>O Monolog funciona com uma arquitetura simples mas poderosa: um <strong>Logger</strong> recebe mensagens, passa pelos <strong>Handlers</strong> (que decidem aonde enviá-las) e pelos <strong>Formatters</strong> (que definem como aparecem). Além disso, <strong>Processors</strong> adicionam contexto às mensagens, como ID de requisição ou informações de usuário.</p>
<pre><code class="language-php"><?php
require 'vendor/autoload.php';
use Monolog\Logger;
use Monolog\Handlers\StreamHandler;
use Monolog\Formatters\LineFormatter;
// Criar logger
$logger = new Logger('minha_app');
// Criar handler que escreve em arquivo
$handler = new StreamHandler(__DIR__ . '/app.log');
// Definir formato
$formatter = new LineFormatter(
"[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n",
"Y-m-d H:i:s"
);
$handler->setFormatter($formatter);
// Adicionar handler ao logger
$logger->pushHandler($handler);
// Usar
$logger->info('Aplicação iniciada');
$logger->warning('Aviso importante', ['user_id' => 123]);
$logger->error('Erro crítico', ['arquivo' => 'user.php', 'linha' => 45]);
?></code></pre>
<p>Este exemplo mostra a estrutura fundamental: criamos um logger, adicionamos um handler com um formatter específico e começamos a registrar eventos. Os níveis de log (info, warning, error) seguem o padrão RFC 5424, permitindo filtragem por severidade.</p>
<h3>Múltiplos Handlers em Paralelo</h3>
<p>Um dos grandes poderes do Monolog é ter múltiplos handlers simultaneamente. Você pode enviar erros críticos por email, warnings para um arquivo, e todas as mensagens para um serviço centralizado.</p>
<pre><code class="language-php"><?php
use Monolog\Handlers\RotatingFileHandler;
use Monolog\Handlers\SwiftMailerHandler;
use Monolog\Level;
$logger = new Logger('api');
// Handler 1: Logs gerais com rotação
$fileHandler = new RotatingFileHandler(__DIR__ . '/logs/app.log', 7);
$fileHandler->setLevel(Level::Debug);
$logger->pushHandler($fileHandler);
// Handler 2: Apenas erros críticos por email
$mailHandler = new SwiftMailerHandler($swift, 'admin@empresa.com');
$mailHandler->setLevel(Level::Error);
$logger->pushHandler($mailHandler);
$logger->debug('Debug info'); // Vai só pro arquivo
$logger->error('Falha na BD'); // Vai pro arquivo E pro email
?></code></pre>
<h2>Configuração Profissional com Monolog</h2>
<h3>Usando Factory Pattern com Configuração</h3>
<p>Em aplicações reais, você não instancia o logger manualmente em cada lugar. Use um container ou factory para gerenciar instâncias globais:</p>
<pre><code class="language-php"><?php
// LoggerFactory.php
class LoggerFactory
{
private static $logger;
public static function create()
{
if (self::$logger === null) {
$logger = new Logger('producao');
// Handler para arquivo com rotação
$rotatingHandler = new RotatingFileHandler(
storage_path('logs/app.log'),
30,
Level::Debug
);
// Adicionar processor para incluir IP e URL
$logger->pushProcessor(function ($record) {
$record->extra['ip'] = $_SERVER['REMOTE_ADDR'] ?? 'CLI';
$record->extra['url'] = $_SERVER['REQUEST_URI'] ?? '';
return $record;
});
$logger->pushHandler($rotatingHandler);
self::$logger = $logger;
}
return self::$logger;
}
}
// Uso em qualquer lugar
$logger = LoggerFactory::create();
$logger->info('Usuário logado', ['usuario_id' => $user->id]);
?></code></pre>
<h3>Diferentes Configurações por Ambiente</h3>
<p>Aplicações profissionais precisam de comportamentos diferentes em desenvolvimento, staging e produção:</p>
<pre><code class="language-php"><?php
class LoggerConfig
{
public static function setup($environment)
{
$logger = new Logger('app');
if ($environment === 'production') {
// Produção: Syslog + Slack para erros críticos
$logger->pushHandler(new SyslogHandler('app'));
$slackHandler = new SlackHandler('seu-webhook-url');
$slackHandler->setLevel(Level::Critical);
$logger->pushHandler($slackHandler);
} else if ($environment === 'development') {
// Desenvolvimento: Arquivo + Console
$logger->pushHandler(new StreamHandler('php://stdout'));
$logger->pushHandler(new StreamHandler(storage_path('logs/debug.log')));
}
return $logger;
}
}
?></code></pre>
<h2>Contexto e Processors Avançados</h2>
<h3>Adicionando Dados Estruturados</h3>
<p>A verdadeira força do Monolog está em contextualizar seus logs com dados estruturados que facilitam buscas e análises posteriores:</p>
<pre><code class="language-php"><?php
$logger = new Logger('transacoes');
$handler = new StreamHandler(__DIR__ . '/transacoes.log');
$handler->setFormatter(new JsonFormatter());
$logger->pushHandler($handler);
// Usar contexto estruturado
$logger->info('Transação processada', [
'transacao_id' => 'TX-12345',
'usuario_id' => 789,
'valor' => 150.50,
'metodo_pagamento' => 'cartao_credito',
'status' => 'aprovada',
'tempo_processamento_ms' => 234
]);
// Output em JSON:
// {"message":"Transação processada","context":{"transacao_id":"TX-12345",...},"level":200}
?></code></pre>
<p>Este formato é ideal para agregar logs com ELK Stack, Datadog ou CloudWatch, permitindo criar dashboards e alertas sofisticados.</p>
<h3>Processadores Customizados</h3>
<p>Processadores adicionam dados automaticamente a cada log sem precisar passar manualmente:</p>
<pre><code class="language-php"><?php
$logger->pushProcessor(function ($record) {
$record->extra['memory_usage_mb'] = round(memory_get_usage(true) / 1024 / 1024, 2);
$record->extra['execution_time_ms'] = round((microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']) * 1000, 2);
$record->extra['request_id'] = $_SERVER['HTTP_X_REQUEST_ID'] ?? uniqid();
return $record;
});
$logger->info('Requisição processada');
// Automaticamente inclui memory_usage, tempo de execução e request_id
?></code></pre>
<h2>Conclusão</h2>
<p>Você aprendeu que o Monolog segue uma arquitetura clara de Logger → Handlers → Formatters, permitindo flexibilidade total na forma como seus logs são capturados e distribuídos. Em segundo lugar, dominar configuração profissional com factories, ambientes diferentes e contexto estruturado transforma logs de ruído em informação acionável. Por fim, utilize processadores para adicionar dados automaticamente, criando trilhas auditáveis que facilitam debugging e monitoramento em produção. O Monolog não é apenas uma ferramenta de logging — é sua seguradora contra os imprevistos do código em produção.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://seldaek.github.io/monolog/" target="_blank" rel="noopener noreferrer">Documentação Oficial Monolog</a></li>
<li><a href="https://symfony.com/doc/current/logging.html" target="_blank" rel="noopener noreferrer">Symfony Logging Documentation</a></li>
<li><a href="https://laravel.com/docs/logging" target="_blank" rel="noopener noreferrer">Laravel Logging Guide</a></li>
<li><a href="https://www.php-fig.org/psr/psr-3/" target="_blank" rel="noopener noreferrer">PHP Standards: PSR-3 Logger Interface</a></li>
<li><a href="https://martinfowler.com/articles/patterns-of-distributed-systems/index.html" target="_blank" rel="noopener noreferrer">Martin Fowler - Structured Logging</a></li>
</ul>