Logs no Nginx: access_log, error_log, formatos e diagnóstico

Capítulo 8

Tempo estimado de leitura: 10 minutos

+ Exercício

O que são access_log e error_log (e por que você precisa dos dois)

No Nginx, os logs se dividem principalmente em dois tipos:

  • access_log: registra cada requisição HTTP processada (método, URL, status, bytes, tempo, user-agent, etc.). É a base para auditoria, métricas e diagnóstico de erros do ponto de vista do cliente.
  • error_log: registra eventos internos, falhas e avisos do Nginx (problemas de permissão, upstream indisponível, timeouts, erros de configuração). É a base para entender por que algo falhou.

Em geral: access_log mostra o “o que aconteceu” e error_log mostra o “por que aconteceu”.

Interpretando o access_log: campos comuns e leitura rápida

O formato padrão (combined) costuma gerar linhas parecidas com:

203.0.113.10 - - [25/Jan/2026:10:15:42 +0000] "GET /api/health HTTP/1.1" 200 18 "-" "curl/8.0"

Como ler:

  • IP do cliente (pode ser proxy/CDN se você não estiver ajustando headers).
  • timestamp da requisição.
  • request line: método, caminho e protocolo.
  • status: 2xx sucesso, 3xx redirect, 4xx erro do cliente, 5xx erro do servidor.
  • bytes enviados na resposta.
  • referer e user-agent (úteis para identificar robôs, scanners, integrações).

O que o access_log não te conta sozinho

Quando você está usando reverse proxy, um 502/504 no access_log indica falha ao falar com o upstream, mas o detalhe do motivo (timeout, conexão recusada, DNS, etc.) normalmente aparece no error_log.

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

Interpretando o error_log: níveis de severidade e mensagens típicas

O error_log tem níveis de severidade. Do menos para o mais crítico, os mais comuns são:

  • debug: extremamente verboso (usar pontualmente).
  • info: eventos informativos.
  • notice: eventos relevantes, mas não necessariamente problema.
  • warn: algo inesperado, mas o Nginx seguiu funcionando.
  • error: falha ao processar algo (pode afetar requisições).
  • crit: condição crítica.
  • alert: ação imediata pode ser necessária.
  • emerg: o Nginx pode não conseguir operar.

Exemplos de mensagens comuns e o que significam:

  • connect() failed (111: Connection refused) while connecting to upstream: upstream não está ouvindo/está down/porta errada/firewall local.
  • upstream timed out (110: Connection timed out) while reading response header from upstream: upstream demorou demais para responder (timeout de leitura).
  • no live upstreams while connecting to upstream: todos os upstreams do grupo falharam/estão marcados como indisponíveis.
  • open() "/caminho" failed (13: Permission denied): permissão/ownership/SELinux/AppArmor impedindo leitura.
  • directory index of "/dir/" is forbidden: sem index e listagem desabilitada (ou permissão negada).
  • rewrite or internal redirection cycle: loop em rewrite/try_files.

Configurando o nível do error_log

Você pode ajustar o nível para reduzir ruído ou aumentar detalhe durante diagnóstico:

error_log /var/log/nginx/error.log warn;

Em incidentes, aumentar para info ou debug pode ajudar, mas faça isso por tempo limitado (gera muito volume).

Onde configurar logs e como separar por site/serviço

É comum definir logs por server block para facilitar análise:

access_log /var/log/nginx/site_access.log combined; error_log  /var/log/nginx/site_error.log warn;

Isso ajuda a isolar problemas quando há múltiplos domínios/serviços no mesmo Nginx.

Rotação de logs (conceito) e integração com logrotate

Logs crescem continuamente. A rotação evita que um arquivo único fique gigante e melhora retenção/backup.

Como funciona conceitualmente

  • logrotate renomeia o arquivo atual (ex.: access.log vira access.log.1), opcionalmente comprime e cria um novo arquivo vazio.
  • O Nginx precisa reabrir os arquivos para continuar escrevendo no novo arquivo (senão ele pode continuar escrevendo no arquivo renomeado).

Exemplo de configuração típica do logrotate para Nginx

Em muitas distribuições existe um arquivo em /etc/logrotate.d/nginx. Um exemplo conceitual:

/var/log/nginx/*.log { daily rotate 14 missingok notifempty compress delaycompress sharedscripts postrotate     # Faz o Nginx reabrir os logs após a rotação     # (equivalente a enviar USR1 ao master process)     kill -USR1 `cat /run/nginx.pid` 2>/dev/null || true endscript }

Pontos importantes:

  • rotate 14: mantém 14 arquivos rotacionados.
  • compress: comprime logs antigos.
  • postrotate com USR1: força reabertura dos logs.

Criando um log_format personalizado (tempo de resposta, upstream e request id)

Um formato customizado acelera diagnóstico porque coloca na mesma linha: tempo total, upstream usado, status do upstream, tempos do upstream e um identificador de requisição.

Variáveis úteis

  • $request_time: tempo total (segundos, com frações).
  • $upstream_addr: endereço do upstream selecionado (IP:porta).
  • $upstream_status: status retornado pelo upstream (quando aplicável).
  • $upstream_response_time: tempo de resposta do upstream.
  • $upstream_connect_time: tempo para conectar no upstream.
  • $upstream_header_time: tempo até receber headers do upstream.
  • $request_id: id de requisição (nem sempre disponível por padrão; depende de build/módulos). Alternativa comum: usar um header como X-Request-Id.

Passo a passo: definir log_format e usar no access_log

1) Defina um formato (em contexto http):

log_format main_ext 'time=$time_iso8601 ip=$remote_addr host=$host '                    'req="$request" status=$status bytes=$body_bytes_sent '                    'rt=$request_time '                    'ua="$http_user_agent" ref="$http_referer" '                    'up_addr=$upstream_addr up_status=$upstream_status '                    'up_rt=$upstream_response_time up_ct=$upstream_connect_time up_ht=$upstream_header_time '                    'rid=$request_id';

2) Aplique no access_log (por server block ou global):

access_log /var/log/nginx/access.log main_ext;

3) Recarregue a configuração (sem derrubar conexões):

sudo nginx -t sudo systemctl reload nginx

Request ID: quando $request_id não existir

Se $request_id não estiver disponível, uma abordagem prática é propagar um header de correlação vindo do cliente/gateway (ou gerar no upstream). Exemplo: logar o header X-Request-Id:

log_format main_ext 'time=$time_iso8601 ip=$remote_addr host=$host '                    'req="$request" status=$status rt=$request_time '                    'up_addr=$upstream_addr up_status=$upstream_status up_rt=$upstream_response_time '                    'rid=$http_x_request_id';

Se você controla o upstream, ele pode gerar esse ID e devolvê-lo ao Nginx/cliente. Se você tem um gateway anterior (CDN/LB), ele pode injetar o header.

Diagnóstico prático com tail, grep e filtros

Ver em tempo real (tail)

Acompanhar access e error simultaneamente ajuda a correlacionar:

sudo tail -f /var/log/nginx/access.log sudo tail -f /var/log/nginx/error.log

Para ver as duas saídas em paralelo, você pode usar dois terminais ou ferramentas como multitail (se disponível).

Filtrar por status HTTP (404, 502, 504)

Se seu log_format inclui status= fica fácil:

grep ' status=404 ' /var/log/nginx/access.log | tail -n 50 grep ' status=502 ' /var/log/nginx/access.log | tail -n 50 grep ' status=504 ' /var/log/nginx/access.log | tail -n 50

Se você usa formato padrão (status é o penúltimo campo antes de bytes), ainda dá para filtrar, mas é menos robusto. Prefira log_format com chave/valor.

Encontrar a URL mais afetada por 404

grep ' status=404 ' /var/log/nginx/access.log | awk -F'req="' '{print $2}' | awk -F'"' '{print $1}' | awk '{print $2}' | sort | uniq -c | sort -nr | head

Esse pipeline extrai o caminho da requisição e conta ocorrências.

Diagnosticar 502 (Bad Gateway) e 504 (Gateway Timeout) correlacionando com error_log

1) Pegue um horário aproximado e procure no error_log:

grep 'upstream' /var/log/nginx/error.log | tail -n 200

2) Padrões úteis:

  • 502 costuma aparecer com connect() failed, recv() failed, upstream prematurely closed connection.
  • 504 costuma aparecer com upstream timed out (timeout lendo header/corpo).

3) Se você loga up_addr e up_status no access_log, identifique qual upstream falhou:

grep ' status=502 ' /var/log/nginx/access.log | tail -n 20 grep ' status=504 ' /var/log/nginx/access.log | tail -n 20

Procure por up_addr= e compare com o error_log no mesmo intervalo de tempo.

Problemas de permissão (403, 404 “estranho”, e mensagens 13: Permission denied)

Quando o Nginx não consegue ler um arquivo, você pode ver:

  • No access_log: 403 (Forbidden) ou às vezes 404 dependendo do fluxo.
  • No error_log: (13: Permission denied).

Filtre por permissão negada:

grep 'Permission denied' /var/log/nginx/error.log | tail -n 50

O que checar rapidamente:

  • Permissões do arquivo e de todos os diretórios do caminho (precisam de execute x para travessia).
  • Usuário do worker do Nginx (diretiva user) e ownership do conteúdo.
  • Se houver controle adicional (SELinux/AppArmor), os logs do sistema podem complementar o error_log.

Roteiro de troubleshooting por sintoma (com mensagens típicas)

Sintoma: muitos 404 em um endpoint específico

  • Access log: várias linhas com status=404 para o mesmo path.
  • Hipóteses comuns: arquivo/rota inexistente, erro de URL no frontend, tentativa de acessar assets antigos, bots varrendo paths.
  • Passos:
  1. Identifique os paths mais frequentes (pipeline de contagem).
  2. Verifique se o path deveria existir (conteúdo estático) ou se é rota do upstream (API).
  3. Se for estático, procure no error_log por open() ... failed (2: No such file or directory).
  4. Se for API, verifique se o upstream está recebendo a rota correta (compare req= e headers se logados).

Sintoma: 502 Bad Gateway

  • Access log: status=502, frequentemente com up_addr vazio ou preenchido e up_status ausente/0.
  • Error log (típico):
connect() failed (111: Connection refused) while connecting to upstream
  • Hipóteses comuns: serviço upstream parado, porta errada, DNS/resolve errado, upstream reiniciando, limite de conexões.
  • Passos:
  1. Confirme no access_log qual up_addr está sendo usado.
  2. No error_log, procure por connect() failed, no live upstreams, upstream prematurely closed connection.
  3. Teste conectividade local até o upstream (ex.: curl para o endereço/porta do upstream a partir do host do Nginx).
  4. Se o upstream fecha conexão, verifique logs do upstream (aplicação) e limites (workers, backlog, keepalive).

Sintoma: 504 Gateway Timeout

  • Access log: status=504, geralmente com up_rt alto ou vazio e rt alto.
  • Error log (típico):
upstream timed out (110: Connection timed out) while reading response header from upstream
  • Hipóteses comuns: upstream lento, deadlock, consulta lenta no banco, timeout baixo no proxy, rede instável.
  • Passos:
  1. Compare rt (tempo total) com up_rt (tempo do upstream). Se up_rt domina, o gargalo é o upstream.
  2. Verifique no error_log se o timeout é ao conectar ou ao ler headers/corpo.
  3. Correlacione com picos de carga: filtre por endpoints com maior rt.

Sintoma: 403 Forbidden / acesso negado

  • Access log: status=403.
  • Error log (típico):
open() "/var/www/site/arquivo" failed (13: Permission denied)
  • Hipóteses comuns: permissões/ownership incorretos, diretório sem x, regras de acesso, index ausente com listagem proibida.
  • Passos:
  1. Procure (13: Permission denied) no error_log.
  2. Valide permissões do caminho completo (diretórios e arquivo).
  3. Se a mensagem for directory index ... is forbidden, verifique se há arquivo de índice esperado e se a listagem não está habilitada.

Sintoma: “funciona às vezes”, intermitência, upstream alternando

  • Access log: erros 502/504 misturados com 200, possivelmente alternando up_addr.
  • Error log: mensagens de timeout/conexão recusada para um upstream específico.
  • Passos:
  1. Filtre access_log por erro e agrupe por up_addr para achar o nó problemático.
  2. Verifique se o nó tem latência maior (compare up_rt por upstream).
  3. Confirme saúde do serviço naquele upstream (logs da aplicação, recursos, rede).

Dicas práticas para tornar logs mais úteis no dia a dia

  • Padronize log_format com chave/valor (facilita grep e parsing).
  • Inclua tempos (rt, up_rt, up_ct) para separar problema de rede vs lentidão do upstream.
  • Inclua upstream (up_addr, up_status) para identificar rapidamente qual backend falhou.
  • Inclua request id (via $request_id ou header) para correlacionar Nginx ↔ aplicação.
  • Separe logs por serviço quando houver múltiplos sites/APIs no mesmo host.

Agora responda o exercício sobre o conteúdo:

Ao diagnosticar erros 502/504 em um Nginx atuando como reverse proxy, qual abordagem melhor ajuda a identificar a causa raiz do problema?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

O access_log mostra o que ocorreu (ex.: 502/504) e pode indicar o upstream (ex.: up_addr). Já o error_log costuma revelar por que falhou (timeout, connection refused, etc.). Correlacionar os dois acelera o diagnóstico.

Próximo capitúlo

Limites e timeouts no Nginx: protegendo o servidor e evitando travamentos

Arrow Right Icon
Capa do Ebook gratuito Nginx para Iniciantes: Servidor Web, Reverse Proxy e Balanceamento Básico
62%

Nginx para Iniciantes: Servidor Web, Reverse Proxy e Balanceamento Básico

Novo curso

13 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.