viu-pino
v0.2.0
Published
Pino adapter for Viu logging (Kafka + Loki + HTTP API)
Downloads
26
Maintainers
Readme
viu-pino
Pino adapter for Viu logging
✨ Quer ver logs? → Joga no Viu. Viu?
viu-pino é uma biblioteca TypeScript/JavaScript que integra o Pino com o sistema Viu, oferecendo dois modos de transporte:
- HTTP (recomendado): Envia logs via API REST
- Kafka: Envia logs diretamente para o Kafka
🚀 Features
- ✅ Modo HTTP - Não expõe Kafka, autenticação via API Key
- ✅ Modo Kafka - Para alta performance (legacy)
- ✅ Circuit Breaker - Previne connection storms
- ✅ Smart Batching - 100 logs ou 1000ms (auto-flush)
- ✅ Correlation IDs - Rastreamento de requisições
- ✅ Express Middleware - Integração nativa
- ✅ TypeScript - Type-safe com definições completas
- ✅ ESM + CommonJS - Suporte dual module
- ✅ Pino Performance - Ultra-rápido e eficiente
📦 Instalação
npm install viu-pino
# or
yarn add viu-pino
# or
pnpm add viu-pino
# or
bun add viu-pino🎯 Quick Start
Modo HTTP (Recomendado)
import { ViuPino, TransportMode } from 'viu-pino';
const logger = new ViuPino({
serviceName: 'my-api',
environment: 'production',
transportMode: TransportMode.HTTP,
apiUrl: 'http://localhost:3000', // URL do backend VIU
apiKey: 'viu_live_xxx', // Gere no dashboard
});
await logger.initialize();
// Logging estruturado
logger.info('User logged in', { userId: '123', ip: '192.168.1.1' });
logger.error('Payment failed', new Error('Insufficient funds'), { amount: 99.90 });Modo Kafka (Legacy/Alternativo)
import { ViuPino, TransportMode } from 'viu-pino';
const logger = new ViuPino({
serviceName: 'my-api',
environment: 'production',
transportMode: TransportMode.KAFKA,
kafkaBrokers: 'kafka.example.com:9092',
kafkaTopic: 'logs.tenant-id',
kafkaUsername: 'tenant_user',
kafkaPassword: 'secure-password',
});
await logger.initialize();
logger.info('Application started', { version: '1.2.3' });📝 Exemplos de Uso
Níveis de Log
INFO - Sem contexto
await logger.info('Application started');
await logger.info('User logged in successfully');
await logger.info('Database connection established');INFO - Com contexto
await logger.info('User logged in', {
userId: '123',
email: '[email protected]',
loginMethod: 'oauth'
});
await logger.info('Request processed', {
method: 'GET',
path: '/api/users',
responseTime: 45,
statusCode: 200
});ERROR - Sem contexto (apenas mensagem)
await logger.error('Something went wrong');
await logger.error('Database connection failed');ERROR - Com objeto Error
try {
await processPayment(order);
} catch (err) {
await logger.error('Payment processing failed', err as Error);
}ERROR - Com Error + contexto adicional
try {
await processPayment(order);
} catch (err) {
await logger.error('Payment processing failed', err as Error, {
orderId: order.id,
amount: order.total,
currency: 'BRL',
userId: order.userId
});
}WARNING - Sem contexto
await logger.warn('High memory usage detected');
await logger.warn('API rate limit approaching');WARNING - Com contexto
await logger.warn('Slow query detected', {
query: 'SELECT * FROM users',
duration: 2500,
threshold: 1000
});
await logger.warn('Cache miss', {
key: 'user:123',
operation: 'getUserProfile',
fallback: 'database'
});DEBUG - Sem contexto
await logger.debug('Entering authentication flow');
await logger.debug('Cache lookup performed');DEBUG - Com contexto
await logger.debug('Processing request', {
headers: req.headers,
body: req.body,
query: req.query
});
await logger.debug('Database query executed', {
sql: 'SELECT * FROM users WHERE id = ?',
params: [userId],
duration: 12
});Outros níveis
// FATAL - Erros críticos que causam shutdown
await logger.fatal('Critical system failure', {
error: 'Out of memory',
freeMemory: 0
});🔐 Produção com Autenticação SASL
import { ViuPino, TransportMode } from 'viu-pino';
const logger = new ViuPino({
serviceName: 'my-api',
environment: 'production',
transportMode: TransportMode.KAFKA,
kafkaBrokers: 'viu-kafka.example.com:9092',
kafkaTopic: 'logs.production',
kafkaUsername: 'viu_tenant123abc',
kafkaPassword: 'your-secure-password',
kafkaSaslMechanism: 'scram-sha-256',
kafkaSecurityProtocol: 'SASL_SSL',
});🌍 Configuração via Environment Variables
# Modo HTTP
export VIU_TRANSPORT_MODE=http
export VIU_SERVICE_NAME=my-api
export VIU_ENVIRONMENT=production
export VIU_API_URL=http://localhost:3000
export VIU_API_KEY=viu_live_xxx
# Modo Kafka
export VIU_TRANSPORT_MODE=kafka
export VIU_KAFKA_BROKERS=kafka.example.com:9092
export VIU_KAFKA_TOPIC=logs.production
export VIU_KAFKA_USERNAME=viu_tenant123abc
export VIU_KAFKA_PASSWORD=your-secure-password🔄 Integração com Express
import express from 'express';
import { viuCorrelationMiddleware } from 'viu-pino/express';
import { ViuPino, TransportMode } from 'viu-pino';
const app = express();
// Middleware para correlation IDs
app.use(viuCorrelationMiddleware({
serviceName: 'my-api',
environment: 'production',
transportMode: TransportMode.HTTP,
apiUrl: 'http://localhost:3000',
apiKey: 'viu_live_xxx',
}));
const logger = new ViuPino({
serviceName: 'my-api',
transportMode: TransportMode.HTTP,
apiUrl: 'http://localhost:3000',
apiKey: 'viu_live_xxx',
});
app.get('/users/:id', async (req, res) => {
await logger.info('Fetching user', { userId: req.params.id });
res.json({ userId: req.params.id });
});🔗 Rastreamento e Correlation IDs
O viu-pino gera automaticamente IDs de rastreamento para todos os logs:
IDs Gerados Automaticamente
await logger.info('User action', { userId: '123' });
// Gera automaticamente:
// - correlation_id: UUID único da requisição
// - trace_id: UUID para rastreamento distribuído (reutiliza correlation_id)
// - span_id: UUID (16 chars) para operações individuaisOrdem de Prioridade para IDs
- Explícito via ViuPino setter: Valor definido manualmente
- Headers HTTP: Extraído via middleware ou
setTraceHeaders() - Auto-geração: UUID gerado automaticamente (padrão)
Definir Manualmente
// Definir IDs globalmente
ViuPino.correlationId = 'custom-correlation-123';
ViuPino.traceId = 'custom-trace-456';
ViuPino.spanId = 'custom-span-789';
await logger.info('Operation with custom IDs');Detecção Automática de Headers HTTP
import { detectTraceHeaders } from 'viu-pino';
// Headers W3C Trace Context ou Zipkin B3 são detectados automaticamente
const headers = req.headers;
const traceInfo = detectTraceHeaders(headers);
if (traceInfo.correlationId) {
ViuPino.correlationId = traceInfo.correlationId;
}
if (traceInfo.traceId) {
ViuPino.traceId = traceInfo.traceId;
}
if (traceInfo.spanId) {
ViuPino.spanId = traceInfo.spanId;
}
// Ou use o método helper
logger.setTraceHeaders(req.headers);Persistência de IDs
IDs gerados automaticamente são persistidos e reutilizados entre logs:
const logger = new ViuPino({ /* config */ });
await logger.info('First log'); // Gera IDs
await logger.info('Second log'); // Reutiliza IDs
await logger.info('Third log'); // Reutiliza IDs
// Todos os 3 logs compartilham os mesmos correlation_id, trace_id, span_idPara resetar e gerar novos IDs:
ViuPino.resetInstance();
// Próximos logs terão novos IDsFiltragem de Context
Valores null e undefined são automaticamente removidos do contexto:
await logger.info('User event', {
userId: '123',
email: null, // ← Removido
name: 'John Doe',
age: undefined, // ← Removido
status: 'active',
});
// Context enviado: { userId: '123', name: 'John Doe', status: 'active' }Compatibilidade: W3C Trace Context, Zipkin B3, OpenTelemetry
app.get('/users/:id', async (req, res) => { logger.info('Fetching user', { userId: req.params.id }); res.json({ id: req.params.id }); });
app.listen(3000, () => { logger.info('Server started', { port: 3000 }); });
## ⚙️ Configuração
| Opção | Tipo | Descrição | Padrão |
|-------|------|-----------|--------|
| `serviceName` | string | Nome do serviço | (obrigatório) |
| `environment` | string | Ambiente | `'development'` |
| `transportMode` | `'http' \| 'kafka'` | Modo de transporte | `'http'` |
| `apiUrl` | string | URL da API (HTTP mode) | undefined |
| `apiKey` | string | API Key (HTTP mode) | undefined |
| `kafkaBrokers` | string | Endereço Kafka | `'localhost:9092'` |
| `kafkaTopic` | string | Topic Kafka | `'logs.app.raw'` |
| `kafkaUsername` | string | Username SASL | undefined |
| `kafkaPassword` | string | Password SASL | undefined |
| `kafkaSaslMechanism` | string | Mecanismo SASL | `'scram-sha-256'` |
| `kafkaSecurityProtocol` | string | Protocolo | `'SASL_SSL'` |
| `level` | string | Nível do log | `'info'` |
| `batchSize` | number | Tamanho do batch | `100` |
| `batchTimeout` | number | Timeout do batch (ms) | `1000` |
## 📈 Performance
- **Modo HTTP**: Envio imediato, retry automático
- **Modo Kafka**: Batching (100 logs ou 1000ms), compressão gzip
- **Circuit Breaker**: Evita sobrecarga em falhas
- **Pino**: Um dos loggers mais rápidos do Node.js
## 🔒 Segurança
- **Modo HTTP**: API Key no header Authorization
- **Modo Kafka**: SASL_SSL ativado por padrão
- Suporte TLS/SSL completo
- Autenticação: SCRAM-SHA-256, SCRAM-SHA-512, PLAIN
## 📦 Exports
```typescript
// Main export
import { ViuPino, ViuPinoConfig, TransportMode, createViuPino } from 'viu-pino';
// Express middleware
import {
viuCorrelationMiddleware,
getCorrelationId,
getTraceId,
getSpanId
} from 'viu-pino/express';🆚 HTTP vs Kafka
| Aspecto | HTTP | Kafka | |---------|------|-------| | Complexidade | Baixa | Alta | | Exposição Kafka | Não | Sim | | Autenticação | API Key | SASL | | Performance | Boa | Excelente | | Recomendado | Padrão | Alta performance |
🤝 Contributing
Contribuições são bem-vindas!
📄 License
MIT License - see LICENSE para detalhes.
