Dominando a Análise de Logs do Nginx para Solução de Problemas Eficiente
Desbloqueie uma solução de problemas eficiente dominando os logs de acesso e erro do Nginx. Este guia detalha como configurar formatos de log personalizados para capturar métricas de tempo cruciais, permitindo identificar gargalos de desempenho no Nginx ou no servidor de aplicação upstream. Aprenda a diagnosticar instantaneamente problemas críticos como erros 502 e 504 usando níveis de severidade do log de erro e utilize comandos poderosos do shell (`grep`, `awk`) para filtrar, contar e analisar padrões de tráfego rapidamente.
Dominando a Análise de Logs do Nginx para Solução de Problemas Eficiente
Os logs do Nginx são geralmente a maneira mais rápida de transformar "o site está fora do ar" em um problema específico. O log de acesso informa o que os clientes solicitaram e qual status receberam. O log de erro informa o que o Nginx não conseguiu fazer: conectar a um upstream, ler um certificado, abrir um arquivo, analisar uma configuração ou esperar tempo suficiente por uma resposta do backend.
Uma boa análise de logs do Nginx não se trata de ficar olhando para arquivos até que algo pareça suspeito. Trata-se de fazer uma pergunta específica, filtrar rapidamente e correlacionar o log de acesso com o log de erro e os logs da aplicação upstream. Um 502 no log de acesso é um sintoma. A linha correspondente no log de erro geralmente é o começo da resposta.
1. Fundamentos dos Logs do Nginx: Acesso vs. Erro
O Nginx mantém dois tipos distintos de logs, cada um servindo a uma função crítica e separada:
1.1 O Log de Acesso (access.log)
O Log de Acesso registra detalhes sobre cada requisição que o Nginx processa. É vital para entender o comportamento do usuário, monitorar o fluxo de tráfego e avaliar os tempos de resposta.
Localização Padrão: Geralmente /var/log/nginx/access.log
Propósito: Rastrear interações do cliente, requisições bem-sucedidas, erros do cliente, erros do servidor retornados através do Nginx, bytes enviados, user agents e tempo de requisição, se configurado.
1.2 O Log de Erro (error.log)
O Log de Erro rastreia problemas internos, falhas operacionais e problemas de comunicação que ocorrem durante o ciclo de vida de processamento do Nginx. Este log é a fonte definitiva para solucionar problemas de conectividade do backend e erros de configuração do servidor.
Localização Padrão: Geralmente /var/log/nginx/error.log
Propósito: Rastrear erros do lado do servidor, avisos e eventos do sistema (erros 5xx, falhas na análise de arquivos de configuração).
Níveis de Severidade do Log de Erro
O Nginx usa oito níveis de severidade. Ao solucionar problemas, geralmente você deve começar no nível error ou superior. O nível de severidade é configurado usando a diretiva error_log:
# Define o nível de severidade mínimo como 'warn'
error_log /var/log/nginx/error.log warn;
| Nível | Descrição | Prioridade |
|---|---|---|
| crit | Condições críticas, como uma falha grave em tempo de execução | Mais Alta |
| error | Ocorreu um erro que impediu uma requisição de ser atendida | Alta |
| warn | Algo inesperado aconteceu, mas as operações continuam | Média |
| notice | Condição normal, mas significativa (ex.: reinicialização do servidor) | Baixa |
| info | Mensagens informativas | Mais Baixa |
Existem também os níveis emerg, alert e debug. O debug pode ser extremamente verboso e geralmente requer uma compilação do Nginx com suporte a debug. Use-o para solução de problemas direcionada, não como uma configuração normal de produção.
2. Personalizando Logs de Acesso para Análise de Desempenho
O formato de log de acesso padrão do Nginx, frequentemente chamado de combined, é útil, mas carece de variáveis cruciais de tempo de desempenho. Para solucionar problemas de lentidão de forma eficaz, você deve definir um formato personalizado que capture quanto tempo o Nginx gastou processando a requisição e quanto tempo o servidor upstream levou.
2.1 Definindo um Formato de Log de Desempenho
Use a diretiva log_format (geralmente definida no nginx.conf) para criar um formato personalizado, por exemplo, timing_log:
log_format timing_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time';
server {
listen 80;
server_name example.com;
# Aplica o formato personalizado aqui
access_log /var/log/nginx/timing_access.log timing_log;
# ... resto da configuração
}
| Variável | Descrição | Valor para Solução de Problemas |
|---|---|---|
| $request_time | Tempo total decorrido desde o primeiro byte recebido até o último byte enviado. | Valores altos indicam rede lenta, Nginx lento ou backend lento. |
| $upstream_response_time | Tempo gasto esperando a resposta do servidor upstream (ex.: servidor de aplicação). | Valores altos aqui apontam o backend como o gargalo. |
| $status | Código de status HTTP retornado ao cliente. | Essencial para filtrar erros (4xx, 5xx). |
Considere usar formatação de log JSON quando os logs forem para um sistema centralizado. JSON é mais difícil de ler a olho nu, mas muito mais fácil para ferramentas analisarem de forma confiável. Se você mantiver logs em texto simples, esteja ciente de que os números de campo do awk podem quebrar quando user agents, caminhos de requisição ou campos entre aspas contêm espaços.
Considere também registrar IDs de requisição. Se seu balanceador de carga ou aplicação já envia um cabeçalho de ID de requisição, passe-o adiante e registre-o:
log_format timing_log '$remote_addr [$time_local] '
'"$request" $status $body_bytes_sent '
'request_time=$request_time '
'upstream_time=$upstream_response_time '
'request_id=$request_id '
'upstream=$upstream_addr';
Um ID de requisição permite conectar uma requisição pública lenta a uma entrada de log da aplicação. Sem ele, você está combinando por timestamp, caminho e IP do cliente, o que é possível, mas muito menos agradável.
3. Interpretando Entradas do Log de Acesso
Uma entrada típica usando o formato personalizado pode se parecer com isto (com valores de tempo adicionados no final):
192.168.1.10 - - [10/May/2024:14:30:05 +0000] "GET /api/data HTTP/1.1" 200 450 "-" "Mozilla/5.0" 0.534 0.528
Diagnóstico:
- Código de Status (200): Sucesso.
- Tempo de Requisição (0.534s): O tempo total é de meio segundo.
- Tempo Upstream (0.528s): Quase todo o tempo foi gasto esperando o backend (
0.534 - 0.528 = 0.006sgastos com overhead do Nginx).
Diagnóstico: Para esta requisição, o backend é a provável fonte da latência de 500ms. O overhead do Nginx parece pequeno.
Não generalize a partir de uma única linha. Observe uma amostra de requisições lentas. Se a maioria das requisições lentas tiver $upstream_response_time alto, concentre-se no aplicativo ou na rede upstream. Se $request_time for alto enquanto $upstream_response_time for baixo, o atraso pode ser tempo de upload do cliente, download lento do cliente, comportamento de buffer ou trabalho do lado do Nginx.
Solução de Problemas Usando Códigos de Status
| Faixa de Código de Status | Significado | Ação Típica/Fonte de Log |
|---|---|---|
| 4xx (Erros do Cliente) | O cliente enviou uma requisição inválida ou não autorizada. | Verifique os logs de acesso para alta frequência. Procure por 404 Not Found (arquivos ausentes) ou 403 Forbidden (problemas de permissão). |
| 5xx (Erros do Servidor) | O Nginx ou um servidor upstream falhou ao atender uma requisição válida. | Verifique imediatamente o Log de Erro para entradas correspondentes. |
| 502 Bad Gateway | O Nginx não conseguiu obter uma resposta do upstream. | O log de erro mostrará detalhes (Conexão Recusada, Timeout). |
| 504 Gateway Timeout | O servidor upstream levou muito tempo para responder dentro dos limites de proxy configurados. | O log de erro mostrará avisos de timeout. Investigue a latência do backend antes de aumentar os timeouts. |
Aumentar proxy_read_timeout pode esconder o sintoma enquanto os usuários ainda esperam muito. É válido para endpoints de longa duração, streaming ou operações lentas conhecidas, mas para requisições normais de API, deve primeiro desencadear uma investigação no backend.
4. Diagnosticando Problemas Críticos no Log de Erro
Quando uma requisição resulta em um erro 5xx, o log de acesso informa apenas que o erro ocorreu. O log de erro informa por quê.
Estudo de Caso: 502 Bad Gateway
Um erro 502 é um dos problemas mais comuns ao usar o Nginx como proxy reverso. Quase sempre aponta para o backend estar inativo, sobrecarregado ou inacessível.
Procure por estas mensagens específicas no log de erro:
4.1 Conexão Recusada (Backend Inativo)
Isso indica que o Nginx tentou conectar na porta do backend, mas nada estava ouvindo, significando que o servidor de aplicação (ex.: PHP-FPM, Gunicorn) está parado ou configurado incorretamente.
2024/05/10 14:35:10 [error] 12345#0: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.1.10, server: example.com, request: "GET /test"
- Ação: Verifique se o serviço backend está em execução, se ele escuta na porta ou socket Unix esperado e se o Nginx aponta para o mesmo endereço. Reinicie somente depois de entender por que ele parou.
4.2 Conexão Fechada Prematuramente pelo Upstream (Crash do Backend)
Isso acontece quando o Nginx estabelece uma conexão, mas o servidor backend a encerra antes de enviar uma resposta HTTP completa. Isso geralmente sugere um erro fatal ou crash no código da aplicação.
2024/05/10 14:38:22 [error] 12345#0: *2 upstream prematurely closed connection while reading response header from upstream, client: 192.168.1.10, server: example.com, request: "POST /submit"
- Ação: Verifique os logs de erro nativos do servidor de aplicação (ex.: logs do PHP-FPM, logs do Node.js) para o erro fatal específico.
Aviso: Se o Nginx falhar ao ler seu arquivo de configuração na inicialização, o erro geralmente será enviado diretamente para o stderr ou um arquivo de log de bootstrap, não para o local configurado
error.log. Sempre verifiquejournalctl -xeou os logs do sistema se o Nginx falhar ao iniciar.
Estudo de Caso: 403 Forbidden
Um 403 no log de acesso pode ser causado por autorização da aplicação, regras de acesso do Nginx, permissões do sistema de arquivos ou comportamento de índice de diretório. O log de acesso sozinho não pode dizer qual.
Procure no log de erro por linhas como:
2024/05/10 15:02:01 [error] 12345#0: *12 directory index of "/var/www/site/" is forbidden
Isso significa que o Nginx alcançou um diretório, mas não tinha arquivo de índice para servir e a listagem de diretório está desabilitada. A correção pode ser criar o index.html esperado, ajustar a diretiva index ou rotear a requisição para a aplicação.
Para problemas de permissão, você pode ver:
2024/05/10 15:04:44 [error] 12345#0: *15 open() "/var/www/site/private.txt" failed (13: Permission denied)
Verifique a propriedade do arquivo, permissões de execução do diretório, política SELinux ou AppArmor quando aplicável e o usuário sob o qual os workers do Nginx são executados.
Estudo de Caso: 499 Cliente Fechou a Requisição
O status 499 específico do Nginx significa que o cliente fechou a conexão antes que o Nginx terminasse de responder. É comum quando os usuários navegam para outra página, clientes móveis perdem a conectividade ou um upstream demora tanto que o cliente desiste.
Não trate todo 499 como um bug do Nginx. Observe o tempo. Se muitos 499s tiverem tempo de requisição alto e corresponderem a upstreams lentos, os usuários podem estar abandonando requisições lentas. Se eles acontecerem imediatamente de um cliente ou rede, pode ser comportamento do cliente.
5. Comandos Práticos do Shell para Análise de Logs
Embora sistemas robustos de monitoramento de logs sejam recomendados para produção, a linha de comando do Linux fornece ferramentas poderosas para solução de problemas rápida e em tempo real.
5.1 Monitoramento em Tempo Real
Monitore os logs à medida que as requisições chegam (especialmente útil após implantar uma correção ou testar um novo recurso):
tail -f /var/log/nginx/access.log
# Ou, para erros apenas
tail -f /var/log/nginx/error.log
Para logs rotacionados e compactados, use zgrep:
zgrep '" 50[0-9] ' /var/log/nginx/access.log*.gz
A rotação de logs é importante durante a revisão de incidentes. O erro pode ter ocorrido pouco antes da meia-noite ou antes de um job de rotação compactar o arquivo de ontem.
5.2 Filtrando e Contando Erros
Encontre e conte rapidamente os erros 5xx mais frequentes da última hora ou dia:
# Encontre todas as requisições 5xx
grep '" 50[0-9] ' /var/log/nginx/access.log | less
# Conte a distribuição de erros 5xx (ex.: quantos 502s vs. 504s)
grep '" 50[0-9] ' /var/log/nginx/access.log | awk '{print $9}' | sort | uniq -c | sort -nr
Explicação: awk '{print $9}' isola o código de status HTTP (assumindo formato de log padrão ou combinado onde o status é o 9º campo).
Se você usar um formato de log personalizado, confirme o número do campo antes de confiar na contagem. Uma verificação rápida mais segura é imprimir algumas linhas analisadas:
awk '{print NR, $0; if (NR == 3) exit}' /var/log/nginx/access.log
Para logs JSON, use jq em vez de números de campo:
jq -r 'select(.status >= 500) | .status' /var/log/nginx/access.json \
| sort | uniq -c | sort -nr
5.3 Identificando Requisições Lentas (Requer Formato de Log Personalizado)
Se você implementou o formato timing_log (onde $request_time é o penúltimo campo, ou campo 16 em nosso exemplo):
# Encontre as 10 requisições mais lentas (ex.: requisições levando mais de 1 segundo)
awk '($16 > 1.0) {print $16, $7}' /var/log/nginx/timing_access.log | sort -nr | head -10
Explicação: Este comando imprime o tempo de requisição e a URI ($7) para qualquer requisição que levou mais de 1.0 segundo, ordenado de forma decrescente.
Um formato de tempo de texto simples mais legível usa valores nomeados, como request_time=0.534. Então você pode usar grep para intervalos lentos de forma menos elegante, mas com menos surpresas de número de campo. Para análises sérias, envie logs estruturados para um sistema de logs e consulte percentis por rota.
5.4 Identificando os Principais IPs de Requisição
Útil para detectar possíveis tentativas de DoS, picos de tráfego ou atividade suspeita:
# Encontre os 20 principais IPs fazendo requisições
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -20
Os principais IPs são um ponto de partida, não uma prova de abuso. Um NAT corporativo, edge de CDN ou balanceador de carga pode fazer muitos usuários parecerem uma única fonte. Se o Nginx estiver atrás de um proxy, configure e registre o IP real do cliente cuidadosamente com real_ip_header e intervalos de proxy confiáveis. Nunca confie em cabeçalhos X-Forwarded-For arbitrários da internet aberta.
Um Fluxo Prático de Solução de Problemas
Comece com o sintoma do usuário e uma janela de tempo. "O checkout retornou 502s por volta das 14:35 UTC" é muito mais útil do que "O Nginx está quebrado".
Primeiro, conte os status:
grep '10/May/2024:14:3' /var/log/nginx/access.log \
| awk '{print $9}' | sort | uniq -c | sort -nr
A filtragem por data com logs de texto simples é complicada, e o comando exato depende do seu formato de log. Para uma verificação rápida de incidentes, mesmo uma filtragem aproximada pode mostrar se o problema foi principalmente 502, 504, 403 ou 404.
Em seguida, extraia algumas requisições correspondentes:
grep '" 502 ' /var/log/nginx/access.log | tail -20
Anote o timestamp, URI, tempo upstream e ID de requisição, se presente. Em seguida, pesquise no log de erro ao redor do mesmo timestamp:
grep '14:35' /var/log/nginx/error.log
Se o erro disser connect() failed (111: Connection refused), inspecione o serviço upstream e sua porta. Se disser upstream timed out, inspecione a latência e o enfileiramento do backend. Se disser no live upstreams, inspecione a saúde do upstream, DNS ou configuração do balanceador de carga.
Finalmente, verifique os logs do backend usando o mesmo ID de requisição ou timestamp. O Nginx geralmente informa onde a transferência falhou, mas o log do backend informa por que a aplicação se comportou dessa maneira.
Torne os Logs Úteis Antes da Interrupção
A pior hora para melhorar a registro é durante uma interrupção. Adicione tempo de requisição, tempo upstream, endereço upstream e IDs de requisição antes de precisar deles. Mantenha os logs de acesso e erro separados por site quando um servidor hospeda vários aplicativos. Certifique-se de que a rotação mantenha histórico suficiente para os incidentes que você realmente investiga.
Quando algo quebrar, leia os logs em pares: log de acesso para o que aconteceu, log de erro para o que o Nginx não conseguiu fazer, log de aplicação para o que o upstream fez em seguida. Esse hábito mantém a solução de problemas focada e geralmente leva você à falha real mais rápido do que alterar timeouts ou reiniciar serviços aleatoriamente.