npm package: @kueshi/logify
Description: Logify - Logging padronizado para NestJS, Express, Fastify e Next.js
Latest version: 3.1.4

<!-- Adicione um logo legal aqui -->
<div align="center">
  <img src="URL_DO_SEU_LOGO" width="150px" />
  <h1>@kueshi/logify</h1>
</div>

<div align="center">
  <strong>Biblioteca de logging padronizada, segura e contextual para o ecossistema Node.js.</strong>
</div>

<div align="center">

[![NPM Version](https://img.shields.io/npm/v/@kueshi/logify.svg)](https://www.npmjs.com/package/@kueshi/logify)
[![NPM Downloads](https://img.shields.io/npm/dm/@kueshi/logify.svg)](https://www.npmjs.com/package/@kueshi/logify)
[![License](https://img.shields.io/npm/l/@kueshi/logify.svg)](https://github.com/Kueshi/logify/blob/main/LICENSE)

</div>

---

## 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`, `cpf` sã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](#-instalação)
-   [Uso por Framework](#-uso-por-framework)
    -   [NestJS](#-nest-js)
    -   [Express](#-express)
    -   [Fastify](#-fastify)
    -   [Next.js (API Routes)](#-next-js-api-routes)
    -   [Scripts & Core](#-scripts--core-puro)
-   [Configuração](#️-configuração)
-   [Referência da API](#-referência-da-api)
-   [Como Contribuir](#-como-contribuir)
-   [Licença](#-licença)

---

## 📦 Instalação

```bash
npm install @kueshi/logify
```

**Pré-requisitos:** Node.js >= 16.x

## 🚀 Uso por Framework

<details>
<summary><strong>🦁 NestJS</strong></summary>

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`:

```typescript
// 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 {}
```

```typescript
// 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`.

```typescript
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.

```typescript
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');
  }
}
```

</details>

<details>
<summary><strong>🚀 Express</strong></summary>

### 1. Configuração

O middleware do Logify deve ser registrado **antes** das suas rotas.

```javascript
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`.

```javascript
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 });
});
```

</details>

<details>
<summary><strong>⚡ Fastify</strong></summary>

### 1. Configuração

Use o plugin `logifyFastify` para integrar com o Fastify.

```javascript
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`.

```javascript
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 };
});
```

</details>

<details>
<summary><strong>▲ Next.js (API Routes)</strong></summary>

Ideal para o **Pages Router** (`pages/api`). Para o App Router, use o controle manual.

### 1. Configuração (Wrapper de API)

```javascript
// 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.

```javascript
'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...');
  // ...
}
```

</details>

<details>
<summary><strong>🛠️ Scripts & Core (Puro)</strong></summary>

Para scripts `node` puros, CRONs fora de um framework ou CLIs.

```javascript
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();
```

</details>

---

## ⚙️ 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 conter `headers` (de uma requisição), `corr_id`, `user_id` ou `access_token` (para extrair o `user_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ático `LogifyCore.getPropagationHeaders()`.

-   **`setLoggingContext(params)`**
    Wrapper para o método estático `LogifyCore.setLoggingContext()`.

---

## 🤝 Como Contribuir

Contribuições são bem-vindas! Se você tem uma sugestão ou encontrou um bug, por favor, abra uma [Issue](URL_DO_SEU_REPO/issues) ou envie um [Pull Request](URL_DO_SEU_REPO/pulls).

1.  Faça um Fork do projeto
2.  Crie sua Feature Branch (`git checkout -b feature/AmazingFeature`)
3.  Commit suas mudanças (`git commit -m 'Add some AmazingFeature'`)
4.  Push para a Branch (`git push origin feature/AmazingFeature`)
5.  Abra um Pull Request

---

## 📜 Licença

Este projeto está licenciado sob a Licença MIT. Veja o arquivo [LICENSE](LICENSE) para mais detalhes.