Logs e Monitoramento: Debugando Apps Node na VPS
Levar uma aplicação Node.js do ambiente de desenvolvimento local para um servidor Linux em produção é um dos momentos mais críticos do ciclo de vida de um projeto. Enquanto no seu computador você pode simplesmente olhar o terminal aberto, em uma VPS (Virtual Private Server), a ausência de visibilidade direta transforma qualquer erro em um mistério. Sem logs estruturados e monitoramento adequado, você estará "chutando" causas de falhas, o que resulta em downtime prolongado e frustração.
Neste tutorial técnico, vamos cobrir o stack essencial para garantir que sua aplicação Node.js seja visível, rastreável e estável em produção. Abordaremos desde a configuração do gerenciador de processos até a captura de logs estruturados e a implementação de alertas básicos. O foco é puramente técnico, com comandos prontos para copiar e colar em seu servidor Linux.
1. A Base: PM2 como Gerenciador de Processos
Nunca, em hipótese alguma, rode uma aplicação Node.js em produção usando apenas o comando node app.js. Se o processo cair, ele não reinicia. Se você precisar atualizar o código, precisa matar o processo manualmente e reiniciar, causando interrupções no serviço.
O padrão da indústria para gerenciar processos Node.js é o PM2. Ele atua como um daemon que mantém sua aplicação viva, reinicia-a em caso de falhas e facilita a rotação de logs. A instalação deve ser feita globalmente via npm ou yarn.
npm install -g pm2
Uma vez instalado, o primeiro passo é iniciar sua aplicação com ele, passando o nome da entrada principal do seu projeto (geralmente index.js, server.js ou app.js). É altamente recomendável usar a flag --name para identificar facilmente seu processo na lista.
pm2 start index.js --name "meu-app-node"
Para garantir que sua aplicação inicie automaticamente quando o servidor VPS reiniciar (por exemplo, após atualizações de segurança do sistema operacional), execute o comando de boot script:
pm2 startup systemd
Este comando gerará e executará um script que configura o systemd do Linux para gerenciar o PM2. Após isso, salve o estado atual dos processos:
pm2 save
Agora, vamos verificar se tudo está funcionando. O comando pm2 list mostrará o status de saúde da aplicação. Observe a coluna "restarts". Se esse número estiver subindo sem motivo aparente, é um sinal claro de instabilidade que precisamos investigar.
2. Estruturação de Logs: A Saída do Console
O PM2 captura automaticamente o stdout (saída padrão) e stderr (erros padrão) da sua aplicação Node.js. Por padrão, ele os armazena em arquivos na pasta ~/.pm2/logs/. No entanto, para fins de troubleshooting eficiente, precisamos entender como visualizar esses logs em tempo real e filtrar ruídos.
O comando mais útil para debug imediato é o logs com a opção --lines, que permite ver as últimas centenas de linhas sem poluir a tela:
pm2 logs meu-app-node --lines 500
Você pode usar filtros para isolar erros específicos. Por exemplo, para ver apenas mensagens de erro contendo "ECONNREFUSED" (comum em falhas de conexão com banco de dados):
pm2 logs meu-app-node --err | grep "ECONNREFUSED"
Dica Pro: Se sua aplicação estiver gerando muitos logs de debug ou requisições HTTP detalhadas, o arquivo de log pode crescer rapidamente e consumir o disco da VPS. Configure seu logger (como winston, pino ou morgan) para não logar níveis de "info" em produção, mantendo apenas "error" e "warn". Isso economiza espaço em disco e torna a leitura dos erros reais mais rápida.
3. Logs Estruturados com JSON
Apenas ler logs textuais no terminal não escala bem. À medida que sua aplicação cresce, você precisará analisar padrões: quantos 500 erros por minuto? Qual endpoint está falhando mais? Para isso, a melhor prática é gerar logs estruturados em JSON.
Configure seu logger para emitir JSON. Se estiver usando o winston, por exemplo:
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
defaultMeta: { service: 'meu-app-node' },
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
O PM2 pode interpretar automaticamente logs JSON se estiverem no formato esperado, exibindo-os de forma legível no terminal. Além disso, ter logs em JSON permite o uso de ferramentas poderosas como Elasticsearch, Grafana Loki ou até mesmo scripts simples de Bash para agregação.
Para visualizar esses logs estruturados via PM2, certifique-se de que o PM2 está configurado para parsear JSON. Você pode forçar isso no arquivo ecosystem.config.js:
module.exports = {
apps: [{
name: 'meu-app-node',
script: './index.js',
log_date_format: "YYYY-MM-DD HH:mm:ss",
merge_logs: true,
max_memory_restart: '1G'
}]
};
Reinicie a aplicação com pm2 restart meu-app-node para aplicar as novas configurações.
4. Monitoramento de Recursos do Sistema
Um erro na sua aplicação Node.js nem sempre é culpa do código JavaScript; muitas vezes, é o servidor Linux que está sem recursos. Memória RAM insuficiente pode causar o Killer OOM (Out of Memory), matando seu processo silenciosamente. CPU saturada deixa a aplicação lenta e não responsiva.
O PM2 possui um módulo integrado chamado pm2-metrics que fornece gráficos simples de uso de memória e CPU diretamente no terminal.
npm install -g pm2-metrics
pm2 monit
O comando pm2 monit abre uma interface visual interativa no seu terminal SSH. Ele mostra:
- Uso de memória por processo.
- Uso de CPU em tempo real.
- Número de requisições (se integrado com frameworks web).
Além do PM2, você deve conhecer os comandos nativos do Linux para monitoramento. Em uma VPS Linux, os essenciais são:
topouhtop: Para ver processos em tempo real e identificar gargalos de CPU.free -h: Para verificar a memória disponível. Se o valor "available" estiver próximo de zero, sua aplicação está vazando memória ou o servidor é pequeno demais.df -h: Para verificar se o disco está cheio. Logs não rotacionados podem lotar seu disco em dias.
Se você notar que a memória da aplicação cresce continuamente ao longo do tempo, isso indica um vazamento de memória (memory leak). Nesse caso, pare o servidor e realize um debug com ferramentas como o Chrome DevTools conectadas ao processo Node ou use a flag --inspect.
5. Rotação de Logs: Prevenindo Disk Full
Mesmo com logs estruturados, arquivos crescem. O PM2 não faz rotação de logs por padrão; ele apenas appenda linhas ao arquivo. Se sua VPS tem 10GB de disco e seu app gera 1GB de log por dia, você ficará offline em 10 dias.
A solução mais robusta no Linux é usar o logrotate. Crie um arquivo de configuração para seus logs do PM2. Por exemplo, crie o arquivo /etc/logrotate.d/pm2-node-app:
/home/seu-user/.pm2/logs/*-out.log /home/seu-user/.pm2/logs/*-error.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 user group
}
Este arquivo diz ao sistema para:
- Mover e comprimir (
gzip) os logs diariamente. - Manter apenas as últimas 14 cópias.
- Criar novos arquivos com permissões corretas após a rotação.
Teste a configuração sem executar para ver o que aconteceria:
logrotate -d /etc/logrotate.d/pm2-node-app
Se a saída parecer correta, execute sem o -d para aplicar.
6. Troubleshooting Avançado: Diagnóstico de Falhas
Quando algo falha em produção, você precisa de um método sistemático. Siga este checklist de debug:
6.1. A aplicação não inicia?
Verifique os primeiros 50 linhas do log de erro:
pm2 logs meu-app-node --err -n 50
Erros comuns incluem variáveis de ambiente faltantes (check com process.env), portas já em uso (EADDRINUSE) ou dependências não instaladas.
6.2. A aplicação crasha aleatoriamente?
Verifique o histórico de restarts:
pm2 show meu-app-node
Se os restarts forem frequentes, analise o log imediatamente anterior ao crash. Procure por exceções não tratadas. Se não houver logs claros, ative o modo de debug do Node.js temporariamente no arquivo ecosystem.config.js:
apps: [{
name: 'meu-app-node',
script: './index.js',
exec_mode: "fork", // Garante que é monomodelo para debug fácil
env: {
NODE_ENV: "production"
}
}]
6.3. A aplicação está lenta?
Use o pm2 monit para ver se há picos de CPU. Se a CPU estiver alta, identifique qual rota ou função está causando isso. Em Node.js, operações síncronas pesadas bloqueiam o Event Loop. Verifique seu código por loops grandes ou cálculos complexos na thread principal.
7. Monitoramento Externo e Alertas
O monitoramento local (PM2 + Linux) é vital, mas você precisa de alertas externos. Se a VPS cair ou o PM2 falhar em reiniciar, você precisa saber via email, Slack ou Telegram.
Existem duas abordagens principais:
- Uptime Kuma (Auto-hospedado): Instale um container Docker leve com Uptime Kuma na mesma VPS ou em outra. Configure-o para pingar sua API health check (
/health) a cada 30 segundos. Se falhar, envie uma notificação. - Serviços de Terceiros: Ferramentas como Datadog, New Relic ou até mesmo o PM2 Plus (cloud) oferecem dashboards remotos e alertas inteligentes.
Para implementar um health check simples no Node.js, adicione uma rota na sua aplicação:
app.get('/health', (req, res) => {
res.status(200).json({ status: 'ok', timestamp: new Date() });
});
Isso permite que ferramentas externas verifiquem a saúde da aplicação sem interferir nas rotas principais.
Conclusão
Debugar aplicações Node.js em uma VPS Linux exige disciplina. Não dependa da sorte. Utilize o PM2 para gerenciar processos, configure logs estruturados para análise posterior, implemente logrotate para preservar disco e monitore os recursos do sistema com ferramentas nativas ou integradas.
A combinação de visibilidade imediata (via terminal) e histórico persistente (via logs rotacionados) é o que separa um profissional de TI que passa noites em claro corrigindo erros de um DevOps que dorme tranquilo sabendo que seu sistema está sob controle. Mantenha seus scripts de deploy automatizados, mas nunca esqueça: observabilidade é a chave para a confiança em produção.
Agora, aplique essas configurações na sua próxima VPS e transforme o caos do debugging em uma rotina simples e eficiente.