Introdução: por que a registro de logs é importante em TypeScript
Registro de logs não é apenas gravar eventos em um arquivo. Em aplicações TypeScript modernas, um registro de logs bem configurado é a base para depuração, monitoramento e análise de desempenho. Sem logs de qualidade, o desenvolvedor perde horas reproduzindo erros, e a equipe de operações não consegue identificar rapidamente gargalos.
TypeScript, como uma extensão do JavaScript, fornece tipagem estrita, permitindo criar sistemas de registro de logs mais previsíveis e seguros. No entanto, usar simples console.log() em produção é um antipadrão que leva a ruído de informação e perda de dados importantes.
Neste artigo, abordaremos as melhores práticas de registro de logs em TypeScript: desde a escolha da biblioteca até a estruturação de logs e trabalho com contexto.
Escolha da biblioteca para registro de logs
No ecossistema TypeScript/Node.js, existem várias bibliotecas populares. Vamos considerar três opções principais:
- Winston — a biblioteca mais popular com configuração flexível de transports (saída para console, arquivo, banco de dados). Suporta níveis de log e formatação.
- Pino — uma biblioteca moderna focada em desempenho. Ideal para sistemas de alta carga.
- Bunyan — uma opção menos popular, mas estável. Todos os loggers geram dados em formato JSON.
Para uma aplicação típica em TypeScript, recomendamos Winston ou Pino. Exemplo de configuração do Winston com TypeScript:
import winston from 'winston';
const logger = winston.createLogger({ level: 'info', format: winston.format.json(), transports: [ new winston.transports.Console(), new winston.transports.File({ filename: 'error.log', level: 'error' }), ],});
logger.info('Servidor iniciado', { port: 3000 });Integração com TypeScript: tipos e interfaces
Para obter o máximo da tipagem, crie um wrapper para o logger usando interfaces:
interface LoggerOptions { level?: string; service?: string;}
interface ILogger { info(message: string, meta?: unknown): void; error(message: string, error?: Error): void; warn(message: string, meta?: unknown): void;}Isso permitirá que você controle rigorosamente os tipos de dados transmitidos e evite erros em tempo de compilação.
Níveis de log e seu uso correto
Os níveis de log padrão (do mais crítico ao menos crítico): error, warn, info, debug, trace. É importante manter uma semântica consistente:
- error — apenas para erros irrecuperáveis que exigem atenção do desenvolvedor.
- warn — para situações potencialmente problemáticas que não interrompem o funcionamento da aplicação.
- info — para eventos-chave: inicialização do servidor, processamento de requisição, autenticação bem-sucedida.
- debug — para depuração durante o desenvolvimento. Não ative este nível em produção.
Exemplo de alteração dinâmica do nível dependendo do ambiente:
const logLevel = process.env.NODE_ENV === 'production' ? 'warn' : 'debug';const logger = winston.createLogger({ level: logLevel });Logs estruturados e contexto
Em vez de mensagens de texto, use logs estruturados em formato JSON. Isso permite analisar logs facilmente com ELK stack (Elasticsearch, Logstash, Kibana) ou outros sistemas.
Sempre adicione informações de contexto: ID da requisição, nome do usuário, nome do serviço, timestamp. Exemplo usando Pino:
import pino from 'pino';
const logger = pino({ level: 'info', mixin() { return { service: 'my-api' }; },});
// Adicionando c