@kueshi/logify
v3.1.4
Published
Logify - Logging padronizado para NestJS, Express, Fastify e Next.js
Readme
O Problema
Em arquiteturas de microsserviços, uma única ação de um usuário pode disparar uma cadeia de eventos através de várias APIs, workers em filas (como RabbitMQ/SQS) e tarefas agendadas (CRONs). Rastrear o fluxo completo dessa operação ("tracing") torna-se um desafio. Sem um identificador único que conecte todos os logs, diagnosticar erros e entender o comportamento do sistema é quase impossível.
A Solução: Log Rastreável com Contexto
O Logify resolve isso de forma elegante, garantindo que seus logs tenham rastreabilidade ponta a ponta. Ele gerencia automaticamente um correlation_id e user_id através de AsyncLocalStorage, uma API nativa do Node.js, assegurando que o contexto seja mantido em operações assíncronas.
- Tracing Automático: Gere um
correlation_idúnico para cada requisição HTTP e propague-o automaticamente. - Segurança por Padrão: Dados sensíveis como
password,token,cpfsão automaticamente ofuscados (data masking) nos logs. - Integração Simples: Adicione Logify ao seu projeto NestJS, Express, Fastify ou Next.js com poucas linhas de código.
- Contexto em Workers: Mantenha o contexto de rastreabilidade em workers e jobs assíncronos.
📚 Tabela de Conteúdos
📦 Instalação
npm install @kueshi/logifyPré-requisitos: Node.js >= 16.x
🚀 Uso por Framework
O módulo NestJS é o mais completo, oferecendo Injeção de Dependência, Interceptors globais e Decorators para Workers.
1. Configuração Básica (HTTP)
No seu AppModule e main.ts:
// app.module.ts
import { Module } from '@nestjs/common';
import { LogifyModule } from '@kueshi/logify/nest';
@Module({
imports: [
LogifyModule.forRoot({
serviceName: 'minha-api-nest',
ignoredPaths: ['/health', '/metrics'], // Opcional
}),
],
})
export class AppModule {}// main.ts
import { LogifyService } from '@kueshi/logify/nest';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule, { bufferLogs: true });
// Substitui o logger padrão do NestJS pelo Logify
app.useLogger(app.get(LogifyService));
await app.listen(3000);
}
bootstrap();Resultado: Toda requisição HTTP agora gera logs automáticos de request.start, request.end (com latência) e erros com stack trace, todos com o mesmo correlation_id.
2. Uso em Workers (RabbitMQ / SQS / Cron)
Para manter o correlation_id vindo de uma mensagem de fila, use o decorator @LogifyWorkerContext.
import { LogifyWorkerContext, LogifyService } from '@kueshi/logify/nest';
@Injectable()
export class WorkerService {
constructor(private readonly logify: LogifyService) {}
@RabbitSubscribe({ queue: 'fila-processamento' })
@LogifyWorkerContext() // <--- Mágica: Extrai headers e cria o contexto de log
async handleMessage(msg: any) {
// O contexto já existe! Logs daqui pra frente sairão com o ID da mensagem original.
this.logify.log('Processando mensagem...');
}
}3. Propagação Manual de Contexto (Get / Set)
Às vezes, você precisa obter os IDs para enviá-los a outra API ou forçar um contexto manualmente.
import { LogifyService } from '@kueshi/logify/nest';
@Injectable()
export class ProducerService {
constructor(private readonly logify: LogifyService) {}
async enviarParaFila(dados: any) {
// 1. GET: Recupera os headers atuais para propagar o contexto
const headers = this.logify.getPropagationHeaders();
console.log(`Enviando com ID: ${headers['X-Correlation-Id']}`);
// Exemplo com AMQP
await this.amqpConnection.publish('exchange', 'key', dados, { headers });
}
async processarAlgoManual(payload: any) {
// 2. SET (Plano B): Se não puder usar o Decorator, inicie o contexto manualmente
this.logify.setLoggingContext({
corr_id: payload.traceId,
user_id: 'admin-manual'
});
this.logify.log('Agora estou logando dentro do contexto manual');
}
}1. Configuração
O middleware do Logify deve ser registrado antes das suas rotas.
import express from 'express';
import { createLogifyMiddleware } from '@kueshi/logify/express';
const app = express();
// Registre o middleware
app.use(createLogifyMiddleware({ serviceName: 'api-express' }));
app.get('/', (req, res) => {
// O middleware já logou o início da requisição (request.start)
res.send('Hello World');
// O fim da requisição (request.end) será logado automaticamente
});2. Controle Manual de Contexto (Get / Set)
Fora do NestJS, o controle manual é feito através da classe estática LogifyCore.
import { LogifyCore } from '@kueshi/logify';
app.post('/webhook', (req, res) => {
// SET: Força um contexto baseado no corpo da requisição
LogifyCore.setLoggingContext({
corr_id: req.body.transactionId
});
const logger = new LogifyCore('webhook-handler');
logger.info('Contexto definido manualmente');
// GET: Pega os headers para chamar outra API e propagar o contexto
const headers = LogifyCore.getPropagationHeaders();
// await axios.post('http://outra-api', { ... }, { headers });
res.json({ ok: true });
});1. Configuração
Use o plugin logifyFastify para integrar com o Fastify.
import Fastify from 'fastify';
import { logifyFastify } from '@kueshi/logify/fastify';
const app = Fastify();
// Registre o plugin
app.register(logifyFastify, { serviceName: 'api-fastify' });
app.get('/', async (req, reply) => {
return { hello: 'world' }; // Logs automáticos de request e response
});2. Controle Manual (Get / Set)
Assim como no Express, use a classe estática LogifyCore.
import { LogifyCore } from '@kueshi/logify';
app.get('/manual', async (req, reply) => {
const ctx = LogifyCore.getLoggingContext();
const logger = new LogifyCore('manual-route');
logger.info(`O ID de correlação atual é ${ctx.correlation_id}`);
return { currentId: ctx.correlation_id };
});Ideal para o Pages Router (pages/api). Para o App Router, use o controle manual.
1. Configuração (Wrapper de API)
// pages/api/users.ts
import { withLogifyApi } from '@kueshi/logify/next';
const handler = async (req, res) => {
// Sua lógica de API aqui
res.status(200).json({ name: 'John Doe' });
};
// Envolva seu handler com o withLogifyApi
export default withLogifyApi(handler, { serviceName: 'api-next' });2. Server Actions (App Router)
Em Server Actions, não há middlewares tradicionais, então o controle de contexto deve ser manual.
'use server'
import { LogifyCore } from '@kueshi/logify';
export async function minhaServerAction(data: any) {
// Inicia um novo contexto para este job
LogifyCore.setLoggingContext({ user_id: 'system-action' });
const logger = new LogifyCore('server-action');
logger.info('Executando ação no servidor...');
// ...
}Para scripts node puros, CRONs fora de um framework ou CLIs.
import { LogifyCore } from '@kueshi/logify';
const logger = new LogifyCore('meu-script-batch');
async function run() {
// Inicia o contexto de log para este processo
LogifyCore.setLoggingContext({ corr_id: `batch-${Date.now()}` });
logger.info('Iniciando processamento...');
try {
// ... sua lógica de negócio ...
logger.info('Processamento concluído com sucesso.');
} catch (err) {
logger.error('Falha inesperada no script', { err });
}
}
run();⚙️ Configuração
As opções podem ser passadas para LogifyModule.forRoot() (NestJS), createLogifyMiddleware() (Express), etc.
| Chave | Tipo | Obrigatório | Descrição |
| --------------- | --------- | ----------- | ----------------------------------------------------------------------------------------------------- |
| serviceName | string | Sim | Nome do seu serviço/aplicação. Ele aparecerá em todos os logs. |
| ignoredPaths | string[]| Não | Uma lista de rotas a serem ignoradas pelo log automático (ex: ['/health', '/metrics']). |
| logLevel | string | Não | Nível mínimo de log a ser exibido. Padrão: 'info'. |
| prettyPrint | boolean | Não | Formata os logs em formato legível para humanos. Não recomendado para produção. Padrão: false. |
📖 Referência da API
LogifyCore (Estático)
Disponível em @kueshi/logify. Use para controle manual de contexto em qualquer ambiente.
setLoggingContext(params)Inicia ou sobrescreve o contexto de log atual.params:object- Pode conterheaders(de uma requisição),corr_id,user_idouaccess_token(para extrair ouser_id).
getLoggingContext()Retorna o contexto atual:{ correlation_id: string, user_id: string }.getPropagationHeaders(base?)Retorna um objeto de headers ({ 'X-Correlation-Id': ..., 'X-User-Id': ... }) pronto para ser enviado para outras APIs.base:object(opcional) - Headers existentes para mesclar com os do Logify.
LogifyService (Injetável no NestJS)
Disponível via Injeção de Dependência no NestJS.
log(message, ...args)error(message, error?, ...args)warn(message, ...args)debug(message, ...args)Métodos padrão de log que injetam o contexto automaticamente.getPropagationHeaders()Wrapper para o método estáticoLogifyCore.getPropagationHeaders().setLoggingContext(params)Wrapper para o método estáticoLogifyCore.setLoggingContext().
🤝 Como Contribuir
Contribuições são bem-vindas! Se você tem uma sugestão ou encontrou um bug, por favor, abra uma Issue ou envie um Pull Request.
- Faça um Fork do projeto
- Crie sua Feature Branch (
git checkout -b feature/AmazingFeature) - Commit suas mudanças (
git commit -m 'Add some AmazingFeature') - Push para a Branch (
git push origin feature/AmazingFeature) - Abra um Pull Request
📜 Licença
Este projeto está licenciado sob a Licença MIT. Veja o arquivo LICENSE para mais detalhes.
