Observabilidade em PHP: pare de adivinhar e enxergue tudo com clareza
\n\nQuando sua aplicação PHP começa a ficar lenta, apresentar erros 500 ou simplesmente se comportar de forma estranha, a primeira reação é olhar os logs. Mas os logs (mesmo que perfeitamente estruturados) são apenas uma parte do quebra-cabeça. O desenvolvimento moderno exige muito mais: você precisa saber quanto tempo cada requisição levou, quais serviços externos estão deixando o sistema lento e quanta memória um endpoint específico está consumindo.
\n\nTudo isso é sobre observabilidade. Neste artigo, vamos explorar os três pilares da observabilidade em PHP: tracing, métricas e logs. Você aprenderá a configurar um monitoramento real com exemplos de código e receberá receitas prontas que podem ser implementadas hoje mesmo.
\n\nO que é observabilidade e por que ela é importante para o desenvolvedor PHP?
\n\nObservabilidade (O11y) é a capacidade de entender o estado interno de um sistema com base em seus dados externos. No mundo PHP, isso significa que você pode responder a perguntas como:
\n\n- \n
- Por que uma requisição específica da API levou 5 segundos? \n
- Qual consulta SQL foi a mais lenta na última hora? \n
- Quantas requisições por segundo seu servidor está processando agora? \n
- Onde exatamente a memória está "vazando"? \n
Sem observabilidade, você trabalha no escuro. Com ela, você enxerga cada movimento da sua aplicação. E sim, isso não se aplica apenas a microsserviços em Go ou Java. Um monolito PHP também pode e deve ser "observado".
\n\nTracing em PHP: rastreamento distribuído com OpenTelemetry
\n\nTracing (rastreamento) é a história de uma requisição. Você vê como a requisição percorre sua aplicação, quais funções são chamadas, quais APIs externas são acessadas e quanto tempo é gasto em cada etapa. Em PHP, o padrão utilizado é o OpenTelemetry.
\n\nInstalação do OpenTelemetry para PHP
\n\nPrimeiro, instale os pacotes necessários via Composer:
\n\ncomposer require open-telemetry/opentelemetry\ncomposer require open-telemetry/transport-grpc\ncomposer require open-telemetry/exporter-otlp\n\n\nAgora, configure o tracer básico. Crie o arquivo tracing.php:
// tracing.php\nuse OpenTelemetry\\API\\Globals;\nuse OpenTelemetry\\SDK\\Trace\\TracerProvider;\nuse OpenTelemetry\\SDK\\Trace\\SpanProcessor\\BatchSpanProcessor;\nuse OpenTelemetry\\SDK\\Trace\\Exporter\\ConsoleSpanExporter;\n\nrequire 'vendor/autoload.php';\n\n// Cria o exporter (por enquanto, no console)\n$exporter = new ConsoleSpanExporter();\n$processor = new BatchSpanProcessor($exporter);\n$tracerProvider = new TracerProvider($processor);\n\n// Registra o tracer global\nGlobals::setTracerProvider($tracerProvider);\n\n// Obtém o tracer com o nome da sua aplicação\n$tracer = Globals::tracerProvider()->getTracer('my-php-app');\n\n\nCriando spans no código real
\n\nSuponha que você tenha um controller que processa um pedido. Vamos envolver as operações principais em spans:
\n\n// OrderController.php\nclass OrderController {\n public function createOrder(array $data) {\n $tracer = Globals::tracerProvider()->getTracer('order-service');\n \n // Span principal — toda a requisição\n $span = $tracer->spanBuilder('POST /orders')->startSpan();\n $span->setAttribute('order.id', $data['id'] ?? 'unknown');\n \n try {\n // Span para validar o usuário\n $userSpan = $tracer->spanBuilder('validate.user')->startSpan();\n $user = $this->validateUser($data['user_id']);\n $userSpan->end();\n \n // Span para salvar no banco de dados\n $dbSpan = $tracer->spanBuilder('save.order')->startSpan();\n $order = $this->saveOrder($data);\n $dbSpan->end();\n \n // Span para enviar e-mail\n $emailSpan = $tracer->spanBuilder('send.email')