Módulo de logging profissional para Node.js desenvolvido pela DevOZ. Projetado para ambientes de produção com suporte a OpenTelemetry, saída JSON estruturada, colorização de terminal, e controle dinâmico de níveis de log via HTTP.
O OZLogger foi desenvolvido com o objetivo de criar uma forma padronizada de auditoria em aplicações Node.js, utilizando ferramentas e padrões da indústria como o OpenTelemetry Data Model.
"Garantir o log e auditoria básicos, com o menor footprint possível."
O OZLogger foi projetado com uma filosofia clara: ser o mais leve possível, tanto em consumo de memória quanto de CPU. O foco é apenas externalizar os dados para stdout/stderr e deixar que os coletores de logs (Filebeat, Fluentd, Promtail, etc.) façam o trabalho pesado de transportar, processar e armazenar os logs.
flowchart LR
subgraph App["Aplicação"]
OZLogger["OZLogger\n(mínimo footprint)"]
end
subgraph Output["Saída"]
stdout["stdout/stderr"]
end
subgraph Collectors["Coletores"]
FB["Filebeat"]
FD["Fluentd"]
PT["Promtail"]
end
subgraph Destinations["Destinos"]
ES["Elasticsearch"]
DD["Datadog"]
Loki["Grafana Loki"]
CW["CloudWatch"]
end
OZLogger -->|"≈ 0 overhead"| stdout
stdout --> FB
stdout --> FD
stdout --> PT
FB --> ES
FD --> DD
PT --> Loki
FB --> CW
| Aspecto | Abordagem OZLogger | Benefício |
|---|---|---|
| Memória | Sem buffers internos, sem filas | Memória disponível para a aplicação |
| CPU | Zero processamento de transporte | CPU disponível para a aplicação |
| I/O | Apenas stdout síncrono | Sem conexões de rede, sem arquivos |
| Dependências | Mínimas (apenas @opentelemetry/api) | Menor bundle, menos vulnerabilidades |
| Complexidade | Delega transporte para coletores | Menos código = menos bugs |
Uma das features mais importantes do OZLogger é a capacidade de alterar o nível de log em runtime com tempo de vida (TTL) obrigatório:
# Ativa debug por 5 minutos em produção - sem redeploy!
curl -X POST http://localhost:9898/changeLevel \
-H "Content-Type: application/json" \
-d '{"level": "debug", "duration": 300000}'Por que isso é crítico?
- Debug em produção sem redeploy - Investigue problemas sem derrubar o serviço
- TTL obrigatório - Impede que alguém esqueça o logger em modo debug
- Propagação automática em cluster - Todos os workers mudam simultaneamente
- Zero downtime - Mudança instantânea, reversão automática
- Auditoria Padronizada - Logs estruturados em formato JSON seguindo o padrão OpenTelemetry, permitindo integração com ferramentas de observabilidade como Elasticsearch, Datadog, Splunk, entre outras
- Rastreabilidade - Integração nativa com distributed tracing através de
traceIdespanId, possibilitando correlacionar logs entre diferentes serviços - Compliance - Nível
auditdedicado para logs de auditoria, facilitando conformidade com requisitos regulatórios (LGPD, SOC2, etc.) - Segurança - Funções
mask()efilter()para garantir que dados sensíveis não vazem em logs - Operabilidade - Controle dinâmico de níveis de log via HTTP, permitindo debugging em produção sem redeploy
A saída JSON do OZLogger é compatível com:
| Ferramenta | Integração |
|---|---|
| Elasticsearch/Kibana | Direta via Filebeat ou Logstash |
| Datadog | Via DD Agent ou API |
| Splunk | Via Universal Forwarder |
| AWS CloudWatch | Via CloudWatch Agent |
| Google Cloud Logging | Via Logging Agent |
| Grafana Loki | Via Promtail |
- Características
- Instalação
- Quick Start
- Arquitetura do Projeto
- Estrutura de Arquivos
- Níveis de Log
- Métodos Disponíveis
- Formatos de Saída
- Servidor HTTP Embarcado
- Contexto e Tracing
- Utilitários
- Variáveis de Ambiente
- Exemplos de Uso
- Desenvolvimento
- Testes
- Contribuindo
- Documentação Adicional
- Aviso de Deprecação
- Zero overhead de transporte - Apenas stdout, coletores fazem o resto
- Mínimo footprint de memória - Sem buffers, sem filas internas
- Mínimo footprint de CPU - Sem processamento de transporte
- Dependências mínimas - Apenas
@opentelemetry/api
- Múltiplos níveis de log - debug, info, audit, warn, error
- Saída JSON estruturada - Compatível com OpenTelemetry Data Model
- Saída em texto - Ideal para desenvolvimento local
- Colorização - Cores ANSI configuráveis para terminal
- Servidor HTTP embarcado - Altere níveis de log em runtime
- Suporte a Cluster - Broadcast de eventos entre workers
- Integração OpenTelemetry - traceId e spanId automáticos
- Medição de tempo - Métodos
time()etimeEnd()integrados - Manipulação de dados sensíveis - Funções
mask()efilter() - Tratamento de referências circulares - Serialização JSON segura
- TypeScript nativo - Tipagem completa incluída
- Alteração de nível em runtime - Via HTTP sem redeploy
- TTL obrigatório - Reversão automática ao nível original
- Cluster-aware - Propagação automática para workers
npm install @ozmap/loggerou com Yarn:
yarn add @ozmap/loggerou com pnpm:
pnpm add @ozmap/loggerimport createLogger from '@ozmap/logger';
const logger = createLogger('MeuApp');
logger.info('Aplicação iniciada');
logger.debug('Dados de debug', { userId: 123 });
logger.error('Erro encontrado', new Error('Falha na conexão'));const createLogger = require('@ozmap/logger');
const logger = createLogger('MeuApp');
logger.info('Aplicação iniciada');
logger.debug('Dados de debug', { userId: 123 });flowchart TB
subgraph OZLogger["OZLogger"]
subgraph Core["Logger Core"]
LC1["Gerenciamento de níveis de log"]
LC2["Controle de timers"]
LC3["Manutenção de contexto (tracing)"]
end
Core --> JSON["JSON Formatter"]
Core --> Text["Text Formatter"]
Core --> HTTP["HTTP Server (Runtime)"]
subgraph Utils["Utilities"]
U1[Helpers]
U2[Objects]
U3[Events]
U4[Enums]
U5[Types]
end
end
O projeto está organizado da seguinte forma:
ozlogger/
├── lib/ # Código fonte principal
│ ├── index.ts # Ponto de entrada - exports
│ ├── Logger.ts # Classe principal do Logger
│ │
│ ├── format/ # Formatadores de saída
│ │ ├── index.ts # Factory de formatadores
│ │ ├── json.ts # Formatador JSON estruturado
│ │ └── text.ts # Formatador texto simples
│ │
│ ├── http/ # Servidor HTTP embarcado
│ │ ├── server.ts # Configuração do servidor
│ │ ├── errors.ts # Classe HttpError
│ │ └── routes/
│ │ └── index.ts # Rotas disponíveis
│ │
│ └── util/ # Utilitários
│ ├── Events.ts # Sistema de eventos
│ ├── Helpers.ts # Funções auxiliares
│ ├── Objects.ts # Manipulação de objetos
│ │
│ ├── enum/ # Enumerações
│ │ ├── Colors.ts # Códigos ANSI de cores
│ │ ├── LevelTags.ts # Tags de níveis de log
│ │ ├── LogLevels.ts # Níveis e severidades
│ │ └── Outputs.ts # Tipos de saída
│ │
│ ├── interface/ # Interfaces TypeScript
│ │ ├── LogContext.ts # Contexto de logging
│ │ ├── LoggerColorized.ts # Interface de colorização
│ │ └── LoggerMethods.ts # Métodos do Logger
│ │
│ └── type/ # Tipos TypeScript
│ ├── AbstractLogger.ts # Logger abstrato
│ ├── Event.ts # Tipos de eventos
│ ├── Http.ts # Tipos HTTP
│ └── LogWrapper.ts # Wrapper de logging
│
├── tests/ # Testes automatizados
│ ├── logger.test.ts # Testes principais
│ ├── logger.perf.test.ts # Testes de performance
│ └── utils.test.ts # Testes de utilitários
│
├── dist/ # Código compilado (gerado)
├── package.json # Configurações do pacote
├── tsconfig.json # Configurações TypeScript
├── jest.config.js # Configurações de testes
├── Agents.md # Documentação dos agentes
└── README.md # Esta documentação
Classe principal que implementa toda a lógica de logging:
- Construtor que aceita tag, cliente de log customizado e opção de desabilitar servidor HTTP
- Métodos de log:
debug(),info(),audit(),warn(),error() - Métodos de timing:
time(),timeEnd() - Gerenciamento de contexto:
withContext(),getContext() - Configuração dinâmica de níveis via
configure()echangeLevel() - Factory function
createLogger()para criação simplificada
Formatador que produz logs em JSON estruturado compatível com OpenTelemetry:
- Inclui
severityText,severityNumber,timestamp,body - Suporta
traceIdespanIdpara distributed tracing - Tratamento de referências circulares com
getCircularReplacer()
Formatador para saída em texto simples:
- Formato:
[timestamp][LEVEL] tag mensagem - Ideal para leitura humana durante desenvolvimento
Servidor HTTP embarcado para controle runtime:
- Inicia apenas no processo primário (cluster-aware)
- Porta padrão: 9898
- Processa requisições JSON e text
- Tratamento de erros padronizado
Rotas HTTP disponíveis:
POST /changeLevel- Altera nível de log temporariamente
Sistema de eventos para comunicação inter-processos:
registerEvent()- Registra handlers no processobroadcastEvent()- Transmite para todos os workers
Funções utilitárias diversas:
stringify()/normalize()- Conversão de dadoscolorized()- Factory de colorizaçãolevel(),color(),output()- Leitura de configuraçãodatetime()- Geração de timestampshost()- Parse de configuração do servidorgetCircularReplacer()- Tratamento de referências circulares
Manipulação segura de objetos para logging:
mask()- Ofusca valores sensíveis (usa SHA1 hash)filter()- Remove campos especificados
Os níveis seguem o modelo de severidade do OpenTelemetry:
| Nível | Severidade | Descrição |
|---|---|---|
quiet |
∞ | Suprime todos os logs |
error |
17 | Erros de aplicação |
warn |
13 | Avisos importantes |
audit |
12 | Logs de auditoria |
info |
9 | Informações gerais |
debug |
5 | Debugging detalhado |
Níveis deprecados (serão removidos em 0.3.x):
critical(17) → useerrorhttp(8) → useinfosilly(1) → usedebug
logger.debug(...args: unknown[]): void // Nível DEBUG
logger.info(...args: unknown[]): void // Nível INFO
logger.audit(...args: unknown[]): void // Nível AUDIT
logger.warn(...args: unknown[]): void // Nível WARNING
logger.error(...args: unknown[]): void // Nível ERRORlogger.time(id: string): Logger // Inicia timer
logger.timeEnd(id: string): Logger // Finaliza timer e loga tempo
// Timing com nível específico
logger.debug.timeEnd(id: string) // Loga no nível DEBUG
logger.error.timeEnd(id: string) // Loga no nível ERRORlogger.withContext(ctx: LogContext): Logger // Adiciona contexto
logger.getContext(): LogContext // Recupera contexto atuallogger.changeLevel(level: string): void // Altera nível de log
logger.stop(): Promise<void> // Para servidor HTTP{
"timestamp": "2024-01-15T10:30:00.000Z",
"tag": "MeuApp",
"severityText": "INFO",
"severityNumber": 9,
"body": {
"0": "Mensagem de log",
"1": { "dados": "adicionais" }
},
"traceId": "abc123...",
"spanId": "def456...",
"pid": 12345,
"ppid": 12344
}2024-01-15T10:30:00.000Z [INFO] MeuApp Mensagem de log { dados: "adicionais" }
O logger inclui um servidor HTTP para controle runtime.
| Variável | Descrição | Padrão |
|---|---|---|
OZLOGGER_SERVER |
Porta/endereço | 9898 |
OZLOGGER_HTTP |
Habilita servidor | true |
Formatos de OZLOGGER_SERVER:
9898- Apenas porta:9898- Apenas portalocalhost:9898- Host e porta127.0.0.1:9898- IPv4 e porta[::1]:9898- IPv6 e porta
Via variável de ambiente:
OZLOGGER_HTTP="false"Via código:
const logger = createLogger('app', { noServer: true });curl -X POST http://localhost:9898/changeLevel \
-H "Content-Type: application/json" \
-d '{"level": "debug", "duration": 300000}'O nível retorna ao original após duration milissegundos.
O logger integra automaticamente com OpenTelemetry para distributed tracing:
import { trace, context } from '@opentelemetry/api';
// TraceId e SpanId são adicionados automaticamente aos logs
// quando existe um span ativo no contexto
logger.info('Requisição processada');logger.withContext({
traceId: 'custom-trace-id',
spanId: 'custom-span-id',
attributes: {
userId: 123,
requestId: 'abc'
}
});
logger.info('Log com contexto personalizado');import { mask } from '@ozmap/logger';
const dados = {
usuario: 'admin',
senha: 'secret123',
apiKey: 'key123'
};
const seguro = mask(dados, ['senha', 'apiKey']);
// {
// usuario: 'admin',
// senha: '****************************************',
// apiKey: '****************************************'
// }import { filter } from '@ozmap/logger';
const dados = {
usuario: 'admin',
senha: 'secret123',
email: 'admin@example.com'
};
const seguro = filter(dados, ['senha']);
// {
// usuario: 'admin',
// email: 'admin@example.com'
// }| Variável | Descrição | Valores | Padrão |
|---|---|---|---|
OZLOGGER_LEVEL |
Nível mínimo de log | quiet, error, warn, audit, info, debug |
audit |
OZLOGGER_OUTPUT |
Formato de saída | json, text |
json |
OZLOGGER_COLORS |
Colorização no terminal | true, false |
false |
OZLOGGER_DATETIME |
Incluir timestamp | true, false |
false |
OZLOGGER_SERVER |
Endereço do servidor HTTP | [host]:port |
9898 |
OZLOGGER_HTTP |
Habilitar servidor HTTP | true, false |
true |
The available logging methods are presented in hierarchy level order.
.debug(...messages: any[]).info(...messages: any[]).audit(...messages: any[]).warn(...messages: any[]).error(...messages: any[])
There are also timing methods available:
.time(id: string).timeEnd(id: string)
Here is a simple code snippet example of using it with typescript:
import createLogger from '@ozmap/logger';
// Initialize and configure the logging facility
const logger = createLogger();
// Example of simple debug log
logger.debug("Simple test log");Or if you are using it with javascript:
const createLogger = require('@ozmap/logger');
// Initialize and configure the logging facility
const logger = createLogger();
// Example of simple debug log
logger.debug("Simple test log");You can also use it to time operations:
import createLogger from '@ozmap/logger';
// Initialize and configure the logging facility
const logger = createLogger();
// Example of timing an operation
logger.time("test-operation");
// ... some code here ...
logger.timeEnd("test-operation");By default, timing logs are output at the INFO level, but you can change this by chaining the level method beforehand:
import createLogger from '@ozmap/logger';
// Initialize and configure the logging facility
const logger = createLogger();
// Example of timing an operation with custom log level
logger.debug.time("test-operation");
// ... some code here ...
logger.debug.timeEnd("test-operation");The logger module also starts an HTTP server on port 9898 by default.
This server can be used to change the log level at runtime without having to restart your application.
The server can be disabled by setting the OZLOGGER_HTTP="false" environment variable.
Or passing it as an option when creating the logger itself.
import createLogger from '@ozmap/logger';
// Initialize and configure the logging facility
const logger = createLogger({ noServer: true });You can change log levels by setting the OZLOGGER_LEVEL environment variable on your deployment.
OZLOGGER_LEVEL="debug"Or alternatively you can make an HTTP request to the logger's server to change the log level at runtime without restarting your application.
POST http://localhost:9898/changeLevel
{
"level": "<log-level>",
"duration": <milliseconds>
}
curl -L -X POST -H 'Content-Type: application/json' -d '{"level":"<log-level>","duration":<milliseconds>}' http://localhost:9898/changeLevel
IMPORTANT: If you have disabled the HTTP server, you will not be able to change the log level at runtime.
When changing the log level at runtime, you must specify a duration (in milliseconds) for how long the new log level should be active. Afterwards, the log level will revert to the default level set in the environment variable OZLOGGER_LEVEL or to 'INFO' if not set.
Since the logger module is primarily designed for production use and performance, it comes with non friendly defaults for development purposes.
Out of the box, the logger will output messages in a JSON format without colors or pretty printing.
It is recommended for development only purposes to set the OZLOGGER_COLORS="true" and OZLOGGER_OUTPUT="text" environment variables to enable colored and easier to read logs.
Another option that can be useful during development is to set the OZLOGGER_DATETIME="true" environment variable to enable timestamped logs.
When running tests, you can come across situations where the HTTP port 9898 is already in use by another instance of the logger module. Because of this, it is recommended to disable the HTTP server during tests by setting the OZLOGGER_HTTP="false" environment variable.
Besides that, if you want to avoid cluttering your test output with log messages, you can set the OZLOGGER_LEVEL="quiet" environment variable to suppress all log messages.
IMPORTANTE: É obrigatório executar os testes e verificar a cobertura de código antes de enviar qualquer alteração.
# Com npm
npm test
# Com yarn
yarn test
# Com pnpm
pnpm test
# Modo watch (desenvolvimento)
npm run test:watchA cobertura de código é um requisito obrigatório para todas as contribuições. Execute:
# Executar testes com cobertura
npm test -- --coverage
# Com yarn
yarn test --coverage
# Com pnpm
pnpm test -- --coverageO projeto utiliza Jest com a seguinte configuração:
// jest.config.js
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
collectCoverageFrom: [
'lib/**/*.ts',
'!lib/**/*.d.ts'
],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80
}
}
};# Recomendado para testes
OZLOGGER_HTTP="false" # Desabilita servidor HTTP
OZLOGGER_LEVEL="quiet" # Suprime todos os logstests/
├── logger.test.ts # Testes da classe Logger
├── logger.perf.test.ts # Testes de performance
└── utils.test.ts # Testes dos utilitários (mask, filter)
- Todos os testes existentes devem passar
- Novos recursos devem ter testes correspondentes
- Cobertura de código não pode diminuir
- Testes devem ser executados com
OZLOGGER_HTTP=false
- Node.js 20+
- npm, yarn ou pnpm
# Clonar repositório
git clone https://github.com/ozmap/ozlogger.git
cd ozlogger
# Instalar dependências
npm install # ou yarn ou pnpm install
# Executar build
npm run build
# Executar testes
npm test| Script | Descrição |
|---|---|
npm run build |
Compila TypeScript |
npm run build:watch |
Compila em modo watch |
npm run test |
Executa testes |
npm run test:watch |
Testes em modo watch |
npm run lint |
Executa linter |
npm run format |
Formata código com Prettier |
- Fork o repositório
- Crie uma branch (
git checkout -b feature/nova-funcionalidade) - Faça suas alterações
- Execute os testes (
npm test -- --coverage) - Commit suas mudanças (
git commit -m 'feat: adiciona nova funcionalidade') - Push para a branch (
git push origin feature/nova-funcionalidade) - Abra um Pull Request
Para informações mais detalhadas, consulte:
- Quick Guide - Guia rápido com exemplos práticos
- Arquitetura - Detalhes da arquitetura interna
- Análise: Sistema HTTP - Análise profunda do servidor HTTP
- Análise: Process Hang - Análise técnica do problema de processo pendurado
- Melhorias - Lista de melhorias planejadas
- Problemas Conhecidos - Issues e workarounds
- Agents - Descrição dos agentes/componentes