@jmlq/logger 0.1.0-alpha.8 → 0.1.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/architecture.md +171 -0
- package/install.md +367 -0
- package/package.json +4 -2
package/architecture.md
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Arquitectura del Paquete @jmlq/logger
|
|
2
|
+
|
|
3
|
+
## Visión General
|
|
4
|
+
|
|
5
|
+
El paquete `@jmlq/logger` está diseñado siguiendo los principios de **Arquitectura Limpia**, proporcionando un sistema de logging extensible y desacoplado que permite registrar logs en múltiples destinos mediante plugins y soporta enmascarado de datos sensibles (PII - Personally Identifiable Information).
|
|
6
|
+
|
|
7
|
+
## Principios de Diseño
|
|
8
|
+
|
|
9
|
+
- **Separación de responsabilidades**: Cada capa tiene una responsabilidad específica
|
|
10
|
+
- **Inversión de dependencias**: Las capas internas no dependen de las externas
|
|
11
|
+
- **Extensibilidad**: Sistema de plugins para diferentes adaptadores de persistencia
|
|
12
|
+
- **Testabilidad**: Arquitectura que facilita la creación de pruebas unitarias
|
|
13
|
+
- **Configurabilidad**: Múltiples opciones de configuración mediante variables de entorno
|
|
14
|
+
|
|
15
|
+
## Estructura de Capas
|
|
16
|
+
|
|
17
|
+
### 📁 Domain (Capa de Dominio)
|
|
18
|
+
|
|
19
|
+
La capa más interna que contiene la lógica de negocio pura, sin dependencias externas.
|
|
20
|
+
|
|
21
|
+
#### **Entities & Value Objects**
|
|
22
|
+
|
|
23
|
+
- [`LogLevelVo`](src/domain/value-objects/log-level.vo.ts): Objeto de valor que representa los niveles de log
|
|
24
|
+
|
|
25
|
+
#### **Ports (Interfaces)**
|
|
26
|
+
|
|
27
|
+
- [`ILoggerPort`](src/domain/ports/logger.port.ts): Contrato principal del logger
|
|
28
|
+
- [`ILogDatasourcePort`](src/domain/ports/log-datasource.port.ts): Contrato para fuentes de datos
|
|
29
|
+
- [`ILoggerServicePort`](src/domain/ports/logger-service.port.ts): Contrato para servicios de logging
|
|
30
|
+
- [`IPiiRedactorPort`](src/domain/ports/pii-redactor.port.ts): Contrato para enmascarado PII
|
|
31
|
+
- [`ILoggerFactoryConfigPort`](src/domain/ports/logger-factory-config.port.ts): Contrato de configuración del factory
|
|
32
|
+
|
|
33
|
+
#### **Services (Servicios de Dominio)**
|
|
34
|
+
|
|
35
|
+
- [`LogLevelService`](src/domain/services/log-level.service.ts): Lógica para manejo de niveles de log
|
|
36
|
+
- [`MessageNormalizerService`](src/domain/services/message-normalizer.service.ts): Normalización de mensajes
|
|
37
|
+
- [`PiiPatternService`](src/domain/services/pii-pattern.service.ts): Gestión de patrones PII
|
|
38
|
+
- [`PiiRedactorService`](src/domain/services/pii-redactor.service.ts): Enmascarado de datos sensibles
|
|
39
|
+
|
|
40
|
+
#### **Types & DTOs**
|
|
41
|
+
|
|
42
|
+
- **Request**: [`SaveLogProps`](src/domain/request/save-log.props.ts), [`GetLogsFilterProps`](src/domain/request/get-logs-filter.props.ts), [`PiiOptionsProps`](src/domain/request/pii-options.props.ts)
|
|
43
|
+
- **Response**: [`LogResponse`](src/domain/response/log.response.ts)
|
|
44
|
+
- **Types**: [`LogMessageType`](src/domain/types/log-message.type.ts)
|
|
45
|
+
|
|
46
|
+
### 📁 Application (Capa de Aplicación)
|
|
47
|
+
|
|
48
|
+
Orquesta la lógica de negocio y coordina los casos de uso.
|
|
49
|
+
|
|
50
|
+
#### **Use Cases**
|
|
51
|
+
|
|
52
|
+
- [`SaveLogUseCase`](src/application/use-cases/save-log.use-case.ts): Guarda logs en los datasources configurados
|
|
53
|
+
- [`GetLogsUseCase`](src/application/use-cases/get-logs.use-case.ts): Recupera logs con filtros
|
|
54
|
+
- [`FlushBuffersUseCase`](src/application/use-cases/flush-buffers.use-case.ts): Vacía buffers de los datasources
|
|
55
|
+
|
|
56
|
+
#### **Factory**
|
|
57
|
+
|
|
58
|
+
- [`LoggerFactory`](src/application/factory/logger.factory.ts): Factory para crear instancias del logger
|
|
59
|
+
|
|
60
|
+
### 📁 Infrastructure (Capa de Infraestructura)
|
|
61
|
+
|
|
62
|
+
Implementaciones concretas de los contratos definidos en el dominio.
|
|
63
|
+
|
|
64
|
+
#### **Services**
|
|
65
|
+
|
|
66
|
+
- [`DatasourceService`](src/infrastructure/services/datasource.service.ts): Implementación del servicio de datasource
|
|
67
|
+
- [`DataSourceErrorHandlerType`](src/infrastructure/services/data-source-error-handler.type.ts): Manejo de errores de datasources
|
|
68
|
+
|
|
69
|
+
## Flujo de Dependencias
|
|
70
|
+
|
|
71
|
+
```txt
|
|
72
|
+
Infrastructure → Application → Domain
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- **Domain**: No depende de nada, contiene la lógica de negocio pura
|
|
76
|
+
- **Application**: Depende solo del Domain, orquesta los casos de uso
|
|
77
|
+
- **Infrastructure**: Depende del Domain y Application, implementa los contratos
|
|
78
|
+
|
|
79
|
+
## Patrones Implementados
|
|
80
|
+
|
|
81
|
+
### **Factory Pattern**
|
|
82
|
+
|
|
83
|
+
El [`LoggerFactory`](src/application/factory/logger.factory.ts) centraliza la creación de instancias del logger con las configuraciones apropiadas.
|
|
84
|
+
|
|
85
|
+
### **Port-Adapter Pattern**
|
|
86
|
+
|
|
87
|
+
Los ports en el domain definen contratos que son implementados por adaptadores en infrastructure.
|
|
88
|
+
|
|
89
|
+
### **Use Case Pattern**
|
|
90
|
+
|
|
91
|
+
Cada operación principal está encapsulada en un caso de uso específico con un método `execute()`.
|
|
92
|
+
|
|
93
|
+
### **Dependency Injection**
|
|
94
|
+
|
|
95
|
+
Las dependencias se inyectan a través de constructores, facilitando el testing y la flexibilidad.
|
|
96
|
+
|
|
97
|
+
## Sistema de Plugins
|
|
98
|
+
|
|
99
|
+
El logger soporta múltiples adaptadores de persistencia:
|
|
100
|
+
|
|
101
|
+
- **Filesystem**: `@jmlq/logger-plugin-fs`
|
|
102
|
+
- **MongoDB**: `@jmlq/logger-plugin-mongo`
|
|
103
|
+
- **PostgreSQL**: `@jmlq/logger-plugin-postgresql`
|
|
104
|
+
|
|
105
|
+
Cada plugin implementa los ports definidos en el domain.
|
|
106
|
+
|
|
107
|
+
## Características Principales
|
|
108
|
+
|
|
109
|
+
### **PII (Personally Identifiable Information)**
|
|
110
|
+
|
|
111
|
+
- Enmascarado automático de datos sensibles
|
|
112
|
+
- Patrones configurables y extensibles
|
|
113
|
+
- Soporte para patrones por defecto y personalizados
|
|
114
|
+
|
|
115
|
+
### **Niveles de Log**
|
|
116
|
+
|
|
117
|
+
- debug, info, warn, error, fatal
|
|
118
|
+
- Configuración de nivel mínimo por entorno
|
|
119
|
+
|
|
120
|
+
### **Múltiples Datasources**
|
|
121
|
+
|
|
122
|
+
- Soporte simultáneo para múltiples backends
|
|
123
|
+
- Configuración opcional de cada adaptador
|
|
124
|
+
|
|
125
|
+
### **Configuración Flexible**
|
|
126
|
+
|
|
127
|
+
- Variables de entorno
|
|
128
|
+
- Configuración programática
|
|
129
|
+
- Políticas de retención de datos
|
|
130
|
+
|
|
131
|
+
## Ejemplo de Uso
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
import { LoggerBootstrap } from "@jmlq/logger";
|
|
135
|
+
|
|
136
|
+
const logger = await LoggerBootstrap.create({
|
|
137
|
+
minLevel: "debug",
|
|
138
|
+
pii: {
|
|
139
|
+
enabled: true,
|
|
140
|
+
includeDefaults: true,
|
|
141
|
+
deep: true,
|
|
142
|
+
},
|
|
143
|
+
adapters: {
|
|
144
|
+
fs: { basePath: "./logs" },
|
|
145
|
+
mongo: { url: "mongodb://localhost:27017", dbName: "logs" },
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
await logger.info("User logged in", {
|
|
150
|
+
userId: "12345",
|
|
151
|
+
email: "user@example.com",
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Testing
|
|
156
|
+
|
|
157
|
+
La arquitectura facilita el testing mediante:
|
|
158
|
+
|
|
159
|
+
> - Interfaces claramente definidas
|
|
160
|
+
> - Servicios desacoplados
|
|
161
|
+
> - Casos de uso aislados
|
|
162
|
+
> - Mocks sencillos de implementar
|
|
163
|
+
|
|
164
|
+
## Consideraciones de Rendimiento
|
|
165
|
+
|
|
166
|
+
> - Buffers para escritura asíncrona
|
|
167
|
+
> - Políticas de rotación de archivos
|
|
168
|
+
> - Retención configurable de datos
|
|
169
|
+
> - Procesamiento asíncrono de logs
|
|
170
|
+
|
|
171
|
+
Esta arquitectura asegura mantenibilidad, extensibilidad y testabilidad del sistema de logging, siguiendo las mejores prácticas de clean architecture.
|
package/install.md
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
# Guía de Instalación y Configuración para @jmlq/logger
|
|
2
|
+
|
|
3
|
+
## Instalación
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install @jmlq/logger
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Configuración Básica
|
|
10
|
+
|
|
11
|
+
### NestJS
|
|
12
|
+
|
|
13
|
+
1. Crear el módulo de Logger
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
// src/logger/logger.module.ts
|
|
17
|
+
import { Module, Global } from "@nestjs/common";
|
|
18
|
+
import { ConfigModule, ConfigService } from "@nestjs/config";
|
|
19
|
+
import { LoggerFactory } from "@jmlq/logger";
|
|
20
|
+
|
|
21
|
+
@Global()
|
|
22
|
+
@Module({
|
|
23
|
+
imports: [ConfigModule],
|
|
24
|
+
providers: [
|
|
25
|
+
{
|
|
26
|
+
provide: "LOGGER",
|
|
27
|
+
useFactory: async (configService: ConfigService) => {
|
|
28
|
+
// Configurar datasources según necesidades
|
|
29
|
+
const datasources = [];
|
|
30
|
+
|
|
31
|
+
// Ejemplo: Plugin de filesystem (requiere @jmlq/logger-plugin-fs)
|
|
32
|
+
if (configService.get("LOG_FS_ENABLED") === "true") {
|
|
33
|
+
const { FileSystemDatasource } = await import(
|
|
34
|
+
"@jmlq/logger-plugin-fs"
|
|
35
|
+
);
|
|
36
|
+
datasources.push(
|
|
37
|
+
new FileSystemDatasource({
|
|
38
|
+
basePath: configService.get("LOG_FS_PATH", "./logs"),
|
|
39
|
+
})
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return LoggerFactory.create({
|
|
44
|
+
datasources,
|
|
45
|
+
minLevel: configService.get("LOG_LEVEL", "info"),
|
|
46
|
+
redactorOptions: {
|
|
47
|
+
enabled: true,
|
|
48
|
+
deep: true,
|
|
49
|
+
includeDefaults: true,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
inject: [ConfigService],
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
exports: ["LOGGER"],
|
|
57
|
+
})
|
|
58
|
+
export class LoggerModule {}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
2. Usar en servicios
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
// src/users/users.service.ts
|
|
65
|
+
import { Injectable, Inject } from "@nestjs/common";
|
|
66
|
+
import { ILogger } from "@jmlq/logger";
|
|
67
|
+
|
|
68
|
+
@Injectable()
|
|
69
|
+
export class UsersService {
|
|
70
|
+
constructor(@Inject("LOGGER") private readonly logger: ILogger) {}
|
|
71
|
+
|
|
72
|
+
async createUser(userData: any) {
|
|
73
|
+
try {
|
|
74
|
+
await this.logger.info("Creando usuario", { userData });
|
|
75
|
+
// ... lógica del servicio
|
|
76
|
+
await this.logger.info("Usuario creado exitosamente", {
|
|
77
|
+
userId: result.id,
|
|
78
|
+
});
|
|
79
|
+
return result;
|
|
80
|
+
} catch (error) {
|
|
81
|
+
await this.logger.error("Error al crear usuario", {
|
|
82
|
+
error: error.message,
|
|
83
|
+
userData,
|
|
84
|
+
});
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Express
|
|
92
|
+
|
|
93
|
+
1. Configurar logger en app.js
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
// src/logger.ts
|
|
97
|
+
import { LoggerFactory, LogLevel } from "@jmlq/logger";
|
|
98
|
+
|
|
99
|
+
export const createLogger = async () => {
|
|
100
|
+
const datasources = [];
|
|
101
|
+
|
|
102
|
+
// Configurar datasources según variables de entorno
|
|
103
|
+
if (process.env.LOG_FS_ENABLED === "true") {
|
|
104
|
+
const { FileSystemDatasource } = await import("@jmlq/logger-plugin-fs");
|
|
105
|
+
datasources.push(
|
|
106
|
+
new FileSystemDatasource({
|
|
107
|
+
basePath: process.env.LOG_FS_PATH || "./logs",
|
|
108
|
+
})
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return LoggerFactory.create({
|
|
113
|
+
datasources,
|
|
114
|
+
minLevel: process.env.LOG_LEVEL || LogLevel.INFO,
|
|
115
|
+
redactorOptions: {
|
|
116
|
+
enabled: true,
|
|
117
|
+
deep: true,
|
|
118
|
+
includeDefaults: true,
|
|
119
|
+
patterns: [
|
|
120
|
+
{
|
|
121
|
+
pattern: "\\b\\d{4}-\\d{4}-\\d{4}-\\d{4}\\b",
|
|
122
|
+
replaceWith: "****-****-****-****",
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
2. Middleware de logging
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
// src/middleware/logger.middleware.ts
|
|
134
|
+
import { Request, Response, NextFunction } from "express";
|
|
135
|
+
import { ILogger } from "@jmlq/logger";
|
|
136
|
+
|
|
137
|
+
export const createLoggerMiddleware = (logger: ILogger) => {
|
|
138
|
+
return async (req: Request, res: Response, next: NextFunction) => {
|
|
139
|
+
const startTime = Date.now();
|
|
140
|
+
|
|
141
|
+
await logger.info("Request iniciado", {
|
|
142
|
+
method: req.method,
|
|
143
|
+
url: req.url,
|
|
144
|
+
ip: req.ip,
|
|
145
|
+
userAgent: req.get("User-Agent"),
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
res.on("finish", async () => {
|
|
149
|
+
const duration = Date.now() - startTime;
|
|
150
|
+
const level = res.statusCode >= 400 ? "error" : "info";
|
|
151
|
+
|
|
152
|
+
await logger[level]("Request completado", {
|
|
153
|
+
method: req.method,
|
|
154
|
+
url: req.url,
|
|
155
|
+
statusCode: res.statusCode,
|
|
156
|
+
duration,
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
next();
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
3. Usar en la aplicación
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
// src/app.ts
|
|
169
|
+
import express from "express";
|
|
170
|
+
import { createLogger } from "./logger";
|
|
171
|
+
import { createLoggerMiddleware } from "./middleware/logger.middleware";
|
|
172
|
+
|
|
173
|
+
const app = express();
|
|
174
|
+
const logger = await createLogger();
|
|
175
|
+
|
|
176
|
+
app.use(createLoggerMiddleware(logger));
|
|
177
|
+
|
|
178
|
+
app.get("/users/:id", async (req, res) => {
|
|
179
|
+
try {
|
|
180
|
+
await logger.info("Obteniendo usuario", { userId: req.params.id });
|
|
181
|
+
// ... lógica
|
|
182
|
+
res.json(user);
|
|
183
|
+
} catch (error) {
|
|
184
|
+
await logger.error("Error al obtener usuario", {
|
|
185
|
+
userId: req.params.id,
|
|
186
|
+
error: error.message,
|
|
187
|
+
});
|
|
188
|
+
res.status(500).json({ error: "Internal server error" });
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Configuración de PII (Datos Sensibles)
|
|
194
|
+
|
|
195
|
+
### Patrones Predefinidos
|
|
196
|
+
|
|
197
|
+
El logger incluye patrones comunes para enmascarar datos sensibles:
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
const logger = LoggerFactory.create({
|
|
201
|
+
datasources,
|
|
202
|
+
redactorOptions: {
|
|
203
|
+
enabled: true,
|
|
204
|
+
deep: true, // Busca en objetos anidados
|
|
205
|
+
includeDefaults: true, // Incluye patrones predefinidos (email, teléfono, etc.)
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Patrones Personalizados
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
const logger = LoggerFactory.create({
|
|
214
|
+
datasources,
|
|
215
|
+
redactorOptions: {
|
|
216
|
+
enabled: true,
|
|
217
|
+
deep: true,
|
|
218
|
+
includeDefaults: true,
|
|
219
|
+
patterns: [
|
|
220
|
+
// Tarjetas de crédito
|
|
221
|
+
{
|
|
222
|
+
pattern: "\\b\\d{4}[-\\s]?\\d{4}[-\\s]?\\d{4}[-\\s]?\\d{4}\\b",
|
|
223
|
+
replaceWith: "****-****-****-****",
|
|
224
|
+
},
|
|
225
|
+
// CURP (México)
|
|
226
|
+
{
|
|
227
|
+
pattern: "[A-Z]{4}\\d{6}[HM][A-Z]{5}[A-Z0-9]\\d",
|
|
228
|
+
replaceWith: "****CURP****",
|
|
229
|
+
},
|
|
230
|
+
// Números de cuenta bancaria
|
|
231
|
+
{
|
|
232
|
+
pattern: "\\b\\d{10,20}\\b",
|
|
233
|
+
replaceWith: "****ACCOUNT****",
|
|
234
|
+
},
|
|
235
|
+
// Tokens JWT
|
|
236
|
+
{
|
|
237
|
+
pattern: "eyJ[A-Za-z0-9-_=]+\\.[A-Za-z0-9-_=]+\\.?[A-Za-z0-9-_.+/=]*",
|
|
238
|
+
replaceWith: "****JWT****",
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Filtrado de Registros
|
|
246
|
+
|
|
247
|
+
### Filtros Básicos
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
// Obtener todos los logs de nivel ERROR o superior
|
|
251
|
+
const errors = await logger.getLogs({
|
|
252
|
+
levelMin: LogLevel.ERROR,
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Filtrar por rango de fechas
|
|
256
|
+
const yesterday = Date.now() - 24 * 60 * 60 * 1000;
|
|
257
|
+
const recentLogs = await logger.getLogs({
|
|
258
|
+
since: yesterday,
|
|
259
|
+
until: Date.now(),
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Búsqueda por texto
|
|
263
|
+
const userLogs = await logger.getLogs({
|
|
264
|
+
query: "usuario",
|
|
265
|
+
limit: 50,
|
|
266
|
+
});
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Filtros Avanzados
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
// Combinación de filtros
|
|
273
|
+
const criticalRecentErrors = await logger.getLogs({
|
|
274
|
+
levelMin: LogLevel.ERROR,
|
|
275
|
+
since: Date.now() - 2 * 60 * 60 * 1000, // Últimas 2 horas
|
|
276
|
+
query: "database connection",
|
|
277
|
+
limit: 20,
|
|
278
|
+
offset: 0,
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// Paginación
|
|
282
|
+
const page1 = await logger.getLogs({ limit: 10, offset: 0 });
|
|
283
|
+
const page2 = await logger.getLogs({ limit: 10, offset: 10 });
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Variables de Entorno
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
# Nivel mínimo de logs
|
|
290
|
+
LOG_LEVEL=info
|
|
291
|
+
|
|
292
|
+
# Filesystem
|
|
293
|
+
LOG_FS_ENABLED=true
|
|
294
|
+
LOG_FS_PATH=./logs
|
|
295
|
+
|
|
296
|
+
# MongoDB (si usas @jmlq/logger-plugin-mongo)
|
|
297
|
+
LOG_MONGO_ENABLED=true
|
|
298
|
+
LOG_MONGO_URL=mongodb://localhost:27017
|
|
299
|
+
LOG_MONGO_DB=logs
|
|
300
|
+
|
|
301
|
+
# PostgreSQL (si usas @jmlq/logger-plugin-postgresql)
|
|
302
|
+
LOG_PG_ENABLED=true
|
|
303
|
+
LOG_PG_HOST=localhost
|
|
304
|
+
LOG_PG_PORT=5432
|
|
305
|
+
LOG_PG_DATABASE=logs
|
|
306
|
+
LOG_PG_USERNAME=logger
|
|
307
|
+
LOG_PG_PASSWORD=secret
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Ejemplo Completo
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
import { LoggerFactory, LogLevel } from "@jmlq/logger";
|
|
314
|
+
|
|
315
|
+
// Configuración completa
|
|
316
|
+
const logger = await LoggerFactory.create({
|
|
317
|
+
datasources: [
|
|
318
|
+
// Múltiples datasources
|
|
319
|
+
new FileSystemDatasource({ basePath: "./logs" }),
|
|
320
|
+
new MongoDatasource({ url: "mongodb://localhost:27017", dbName: "logs" }),
|
|
321
|
+
],
|
|
322
|
+
minLevel: LogLevel.DEBUG,
|
|
323
|
+
redactorOptions: {
|
|
324
|
+
enabled: true,
|
|
325
|
+
deep: true,
|
|
326
|
+
includeDefaults: true,
|
|
327
|
+
patterns: [
|
|
328
|
+
{
|
|
329
|
+
pattern: "\\b\\d{4}-\\d{4}-\\d{4}-\\d{4}\\b",
|
|
330
|
+
replaceWith: "****-****-****-****",
|
|
331
|
+
},
|
|
332
|
+
],
|
|
333
|
+
},
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// Uso con diferentes niveles
|
|
337
|
+
await logger.debug("Debug info", { userId: 123 });
|
|
338
|
+
await logger.info("User login", { email: "user@example.com" });
|
|
339
|
+
await logger.warn("High latency", { endpoint: "/api/users", duration: 950 });
|
|
340
|
+
await logger.error("Database error", { error: "Connection timeout" });
|
|
341
|
+
await logger.fatal("System crash", { stack: error.stack });
|
|
342
|
+
|
|
343
|
+
// Filtrar y consultar logs
|
|
344
|
+
const recentErrors = await logger.getLogs({
|
|
345
|
+
levelMin: LogLevel.ERROR,
|
|
346
|
+
since: Date.now() - 24 * 60 * 60 * 1000,
|
|
347
|
+
limit: 100,
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// Limpiar buffers (útil antes de cerrar la aplicación)
|
|
351
|
+
await logger.flush();
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## Plugins Disponibles
|
|
355
|
+
|
|
356
|
+
> - `@jmlq/logger-plugin-fs`: Persistencia en archivos
|
|
357
|
+
> - `@jmlq/logger-plugin-mongo`: Persistencia en MongoDB
|
|
358
|
+
> - `@jmlq/logger-plugin-postgresql`: Persistencia en PostgreSQL
|
|
359
|
+
|
|
360
|
+
Cada plugin se instala por separado según las necesidades de tu aplicación.
|
|
361
|
+
|
|
362
|
+
## Consideraciones de Rendimiento
|
|
363
|
+
|
|
364
|
+
Los logs se procesan de forma asíncrona
|
|
365
|
+
Múltiples datasources escriben en paralelo
|
|
366
|
+
Usa [flush()](./examples/logger-factory.example.ts) antes de cerrar la aplicación para asegurar que todos los logs se persistan
|
|
367
|
+
Configura límites apropiados en las consultas para evitar sobrecarga de memoria
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jmlq/logger",
|
|
3
3
|
"description": "logger package with clean architecture",
|
|
4
|
-
"version": "0.1.0-alpha.
|
|
4
|
+
"version": "0.1.0-alpha.9",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
@@ -35,6 +35,8 @@
|
|
|
35
35
|
"typescript": "^5.2.2"
|
|
36
36
|
},
|
|
37
37
|
"files": [
|
|
38
|
-
"dist"
|
|
38
|
+
"dist",
|
|
39
|
+
"architecture.md",
|
|
40
|
+
"install.md"
|
|
39
41
|
]
|
|
40
42
|
}
|