Logging estruturado Node.js: guia com Winston
Logging estruturado em Node.js com Winston vai além de console.log: saídas em JSON, níveis consistentes e contexto de requisição. Este guia mostra o caminho.
Logging estruturado em Node.js com Winston vai além de console.log: saídas em JSON, níveis consistentes e contexto de requisição. Este guia mostra o caminho.
Logging estruturado em Node.js com Winston significa registrar eventos em formato JSON, com níveis, timestamp e contexto. Isso permite consultas precisas em ferramentas como Elasticsearch e facilita a correlação de erros em produção. Neste guia, você implementa logging estruturado do zero, com foco em uso real e custo de manutenção.
Pré-requisitos: Node.js 18+ e um projeto npm iniciado. Você vai usar o Winston na versão 3.x, a mais estável.
Passo 1: Instalar e configurar o Winston
Instale a dependência com npm install winston. No arquivo logger.js, crie uma instância com transporte de console e formato JSON.
const winston = require('winston');
const logger = winston.createLogger({ level: 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.json() ), transports: [new winston.transports.Console()] });
module.exports = logger;
Dica: defina o nível mínimo via variável de ambiente (process.env.LOG_LEVEL), não fixo no código. Em desenvolvimento, use debug; em produção, info.
Erro comum: esquecer o timestamp(). Sem ele, você perde a ordem cronológica exata dos eventos, essencial para correlacionar falhas.
Passo 2: Usar níveis de forma consistente
O Winston usa níveis npm: error, warn, info, http, verbose, debug, silly. Defina uma convenção e siga-a em todo o código.
logger.info('Usuário autenticado', { userId: 123 }); logger.error('Falha ao processar pagamento', { orderId: 456, error: err.message });
Dica: trate error como algo que exige ação imediata. Se você loga tudo como info, o monitoramento vira ruído.
Erro comum: logar a string de erro sem o objeto. Passe { error: err.message } ou o próprio err para manter o stack trace.
Passo 3: Adicionar contexto de requisição
Em uma API, cada log deve carregar requestId, userId e rota. Use um middleware para gerar e propagar esse contexto.
app.use((req, res, next) => { req.requestId = crypto.randomUUID(); res.on('finish', () => { logger.info('Requisição concluída', { requestId: req.requestId, method: req.method, path: req.path, status: res.statusCode }); }); next(); });
Dica: use crypto.randomUUID() (nativo no Node 18+) para gerar IDs únicos sem dependência extra.
Erro comum: não propagar o requestId para logs internos. Sem ele, você não consegue rastrear uma requisição inteira quando algo falha no meio do caminho.
Passo 4: Logar erros com stack trace
Para erros capturados, use o formato que preserva a pilha. O Winston serializa o Error se você passar o objeto inteiro.
catch (err) { logger.error('Falha ao buscar usuário', { error: err, userId }); }
Dica: teste a saída no console. Se o stack não aparecer, ajuste o formato com winston.format.errors({ stack: true }).
Erro comum: logar err.message apenas. O stack trace é o que diferencia um log útil de um log inútil.
Checklist final
- [ ] Winston instalado e configurado com JSON e timestamp
- [ ] Níveis definidos e usados de forma consistente
- [ ] Contexto de requisição (requestId, userId) em todos os logs
- [ ] Erros logados com stack trace
- [ ] Nível mínimo configurado por ambiente
FAQ
Por que usar logging estruturado em vez de console.log?
console.log gera texto livre, difícil de filtrar e correlacionar. Logging estruturado em JSON permite consultas exatas por campo, como userId ou requestId, em ferramentas de observabilidade.
Winston é melhor que Pino?
Depende do seu caso. Pino é mais rápido e tem menor sobrecarga, mas Winston tem ecossistema maior e mais transportes prontos. Para a maioria das aplicações, Winston resolve bem.
Como configurar o nível de log por ambiente?
Use process.env.LOG_LEVEL como valor do level na configuração. Defina debug em desenvolvimento e info em produção, via variável de ambiente.
Preciso de um serviço externo para visualizar os logs?
Não. O transporte de console já estrutura em JSON. Para produção, você pode enviar para Elasticsearch, Datadog ou qualquer coletor que aceite JSON.
Como evitar logs duplicados em múltiplos transportes?
Use apenas um transporte por ambiente ou configure níveis diferentes para cada um. Transportes duplicados com o mesmo nível geram ruído e custo desnecessário.
O que fazer com logs sensíveis?
Nunca logue senhas, tokens ou dados pessoais. Crie uma função de sanitização que remove campos sensíveis antes de passar para o logger.
Letícia Sampaio Khoury
Editora de Gadgets e Consumo Tech
Testa o gadget no dia a dia real, avalia se vale a grana sem deslumbre de novidade.
Ver todos os artigos →