@jmlq/logger 0.1.0-alpha.1 → 0.1.0-alpha.10
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/README.md +307 -0
- package/architecture.md +171 -0
- package/dist/examples/data-source-service.example.d.ts +3 -0
- package/dist/examples/data-source-service.example.js +174 -0
- package/dist/examples/flush-buffers-use-case.example.d.ts +3 -0
- package/dist/examples/flush-buffers-use-case.example.js +60 -0
- package/dist/examples/get-logs-use-case.example.d.ts +3 -0
- package/dist/examples/get-logs-use-case.example.js +110 -0
- package/dist/examples/index.example.d.ts +8 -0
- package/dist/examples/index.example.js +116 -0
- package/dist/examples/logger-factory.example.d.ts +39 -0
- package/dist/examples/logger-factory.example.js +158 -0
- package/dist/examples/normalize-message.example.d.ts +3 -0
- package/dist/examples/normalize-message.example.js +80 -0
- package/dist/examples/pii-redactor.example.d.ts +3 -0
- package/dist/examples/pii-redactor.example.js +129 -0
- package/dist/examples/save-log-use-case.example.d.ts +3 -0
- package/dist/examples/save-log-use-case.example.js +150 -0
- package/dist/examples/to-log-level.example.d.ts +3 -0
- package/dist/examples/to-log-level.example.js +49 -0
- package/dist/examples/to-pii-regex.example.d.ts +3 -0
- package/dist/examples/to-pii-regex.example.js +75 -0
- package/dist/{presentation/factory/index.d.ts → src/application/factory/create-logger.d.ts} +1 -1
- package/dist/src/application/factory/create-logger.js +29 -0
- package/dist/src/application/factory/index.d.ts +1 -0
- package/dist/{config → src/application/factory}/index.js +1 -2
- package/dist/src/application/factory/logger.factory.d.ts +12 -0
- package/dist/src/application/factory/logger.factory.js +74 -0
- package/dist/src/application/index.d.ts +2 -0
- package/dist/{presentation → src/application}/index.js +1 -0
- package/dist/src/application/use-cases/flush-buffers.use-case.d.ts +6 -0
- package/dist/src/application/use-cases/flush-buffers.use-case.js +13 -0
- package/dist/src/application/use-cases/get-logs.use-case.d.ts +8 -0
- package/dist/src/application/use-cases/get-logs.use-case.js +24 -0
- package/dist/src/application/use-cases/index.d.ts +3 -0
- package/dist/src/application/use-cases/index.js +19 -0
- package/dist/src/application/use-cases/save-log.use-case.d.ts +8 -0
- package/dist/src/application/use-cases/save-log.use-case.js +26 -0
- package/dist/src/domain/index.d.ts +6 -0
- package/dist/src/domain/index.js +22 -0
- package/dist/src/domain/ports/create-logger-options.port.d.ts +7 -0
- package/dist/{config/interfaces/index.js → src/domain/ports/create-logger-options.port.js} +0 -1
- package/dist/src/domain/ports/index.d.ts +6 -0
- package/dist/src/domain/ports/index.js +22 -0
- package/dist/src/domain/ports/log-datasource.port.d.ts +9 -0
- package/dist/src/domain/ports/log-datasource.port.js +2 -0
- package/dist/src/domain/ports/logger-factory-config.port.d.ts +28 -0
- package/dist/src/domain/ports/logger-factory-config.port.js +2 -0
- package/dist/src/domain/ports/logger-service.port.d.ts +19 -0
- package/dist/src/domain/ports/logger-service.port.js +2 -0
- package/dist/src/domain/ports/logger.port.d.ts +10 -0
- package/dist/src/domain/ports/logger.port.js +2 -0
- package/dist/src/domain/ports/pii-redactor.port.d.ts +5 -0
- package/dist/src/domain/ports/pii-redactor.port.js +2 -0
- package/dist/src/domain/request/get-logs-filter.props.d.ts +9 -0
- package/dist/src/domain/request/get-logs-filter.props.js +2 -0
- package/dist/src/domain/request/index.d.ts +5 -0
- package/dist/src/domain/request/index.js +21 -0
- package/dist/src/domain/request/log.props.d.ts +7 -0
- package/dist/src/domain/request/log.props.js +2 -0
- package/dist/src/domain/request/pii-options.props.d.ts +8 -0
- package/dist/src/domain/request/pii-options.props.js +2 -0
- package/dist/src/domain/request/pii-replacement.props.d.ts +5 -0
- package/dist/src/domain/request/pii-replacement.props.js +2 -0
- package/dist/src/domain/request/save-log.props.d.ts +7 -0
- package/dist/src/domain/request/save-log.props.js +2 -0
- package/dist/src/domain/response/index.d.ts +1 -0
- package/dist/{domain/services → src/domain/response}/index.js +1 -1
- package/dist/src/domain/response/log.response.d.ts +7 -0
- package/dist/src/domain/response/log.response.js +2 -0
- package/dist/src/domain/services/index.d.ts +4 -0
- package/dist/{index.js → src/domain/services/index.js} +4 -4
- package/dist/src/domain/services/log-level.service.d.ts +2 -0
- package/dist/src/domain/services/log-level.service.js +27 -0
- package/dist/src/domain/services/message-normalizer.service.d.ts +3 -0
- package/dist/src/domain/services/message-normalizer.service.js +8 -0
- package/dist/src/domain/services/pii-pattern.service.d.ts +2 -0
- package/dist/src/domain/services/pii-pattern.service.js +13 -0
- package/dist/src/domain/services/pii-redactor.d.ts +10 -0
- package/dist/src/domain/services/pii-redactor.js +68 -0
- package/dist/src/domain/services/pii-redactor.service.d.ts +10 -0
- package/dist/src/domain/services/pii-redactor.service.js +68 -0
- package/dist/src/domain/types/index.d.ts +1 -0
- package/dist/src/domain/types/index.js +17 -0
- package/dist/src/domain/types/log-message.type.d.ts +1 -0
- package/dist/src/domain/types/log-message.type.js +2 -0
- package/dist/src/domain/value-objects/index.d.ts +1 -0
- package/dist/src/domain/value-objects/index.js +17 -0
- package/dist/src/domain/value-objects/log-level.vo.d.ts +8 -0
- package/dist/src/domain/value-objects/log-level.vo.js +13 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.js +22 -0
- package/dist/src/infrastructure/datasources/in-memory-log.datasource.d.ts +1 -0
- package/dist/src/infrastructure/datasources/in-memory-log.datasource.js +2 -0
- package/dist/src/infrastructure/datasources/index.d.ts +1 -0
- package/dist/src/infrastructure/datasources/index.js +17 -0
- package/dist/src/infrastructure/services/data-source-error-handler.type.d.ts +5 -0
- package/dist/src/infrastructure/services/data-source-error-handler.type.js +2 -0
- package/dist/src/infrastructure/services/datasource.service.d.ts +15 -0
- package/dist/src/infrastructure/services/datasource.service.js +63 -0
- package/dist/src/infrastructure/services/index.d.ts +2 -0
- package/dist/src/infrastructure/services/index.js +18 -0
- package/dist/tests/application/factory/logger-factory.spec.d.ts +1 -0
- package/dist/tests/application/factory/logger-factory.spec.js +161 -0
- package/dist/tests/application/use-cases/flush-buffers.use-case.spec.d.ts +1 -0
- package/dist/tests/application/use-cases/flush-buffers.use-case.spec.js +38 -0
- package/dist/tests/application/use-cases/get-logs.use-case.spec.d.ts +1 -0
- package/dist/tests/application/use-cases/get-logs.use-case.spec.js +114 -0
- package/dist/tests/application/use-cases/save-log.use-case.spec.d.ts +1 -0
- package/dist/tests/application/use-cases/save-log.use-case.spec.js +138 -0
- package/dist/tests/domain/services/log-level.service.spec.d.ts +1 -0
- package/dist/tests/domain/services/log-level.service.spec.js +68 -0
- package/dist/tests/domain/services/normalize-message.spec.d.ts +1 -0
- package/dist/tests/domain/services/normalize-message.spec.js +83 -0
- package/dist/tests/domain/services/pii-redactor.spec.d.ts +1 -0
- package/dist/tests/domain/services/pii-redactor.spec.js +170 -0
- package/dist/tests/domain/services/to-pii-regex.spec.d.ts +1 -0
- package/dist/tests/domain/services/to-pii-regex.spec.js +82 -0
- package/dist/tests/infrastructure/services/datasource.service.spec.d.ts +1 -0
- package/dist/tests/infrastructure/services/datasource.service.spec.js +128 -0
- package/dist/tests/test-utils/create-pii-redactor-mock.d.ts +5 -0
- package/dist/tests/test-utils/create-pii-redactor-mock.js +10 -0
- package/install.md +367 -0
- package/package.json +33 -10
- package/dist/Composite/index.d.ts +0 -9
- package/dist/Composite/index.js +0 -23
- package/dist/Factory/index.d.ts +0 -5
- package/dist/Factory/index.js +0 -23
- package/dist/config/index.d.ts +0 -2
- package/dist/config/interfaces/index.d.ts +0 -67
- package/dist/config/types/index.d.ts +0 -10
- package/dist/config/types/index.js +0 -13
- package/dist/domain/services/index.d.ts +0 -1
- package/dist/domain/services/pii-redactor.d.ts +0 -27
- package/dist/domain/services/pii-redactor.js +0 -139
- package/dist/index.d.ts +0 -4
- package/dist/interfaces/index.d.ts +0 -35
- package/dist/interfaces/index.js +0 -13
- package/dist/presentation/factory/index.js +0 -74
- package/dist/presentation/index.d.ts +0 -1
- /package/dist/{domain → src/infrastructure}/index.d.ts +0 -0
- /package/dist/{domain → src/infrastructure}/index.js +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# @jmlq/logger
|
|
2
|
+
|
|
3
|
+
Sistema de logging modular y extensible con **Arquitectura Limpia**. Soporta múltiples destinos (archivos, MongoDB, PostgreSQL) y enmascarado automático de datos sensibles (PII).
|
|
4
|
+
|
|
5
|
+
## 📦 Instalación
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Core del logger
|
|
9
|
+
npm install @jmlq/logger
|
|
10
|
+
|
|
11
|
+
# Plugins opcionales (instala según necesites)
|
|
12
|
+
npm install @jmlq/logger-plugin-fs # Para archivos
|
|
13
|
+
npm install @jmlq/logger-plugin-mongo # Para MongoDB
|
|
14
|
+
npm install @jmlq/logger-plugin-postgresql # Para PostgreSQL
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 🚀 Uso Básico
|
|
18
|
+
|
|
19
|
+
### Configuración Simple
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { LoggerFactory, LogLevel } from "@jmlq/logger";
|
|
23
|
+
|
|
24
|
+
// Crear un datasource en memoria (para testing/desarrollo)
|
|
25
|
+
const memoryDatasource = {
|
|
26
|
+
name: "memory",
|
|
27
|
+
async save(log) {
|
|
28
|
+
console.log("LOG:", log);
|
|
29
|
+
},
|
|
30
|
+
async find(filter) {
|
|
31
|
+
return [];
|
|
32
|
+
},
|
|
33
|
+
async flush() {},
|
|
34
|
+
async dispose() {},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Crear el logger
|
|
38
|
+
const logger = LoggerFactory.create({
|
|
39
|
+
datasources: memoryDatasource,
|
|
40
|
+
minLevel: LogLevel.INFO,
|
|
41
|
+
redactorOptions: {
|
|
42
|
+
enabled: true,
|
|
43
|
+
deep: true,
|
|
44
|
+
includeDefaults: true,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Usar el logger
|
|
49
|
+
await logger.info("Usuario conectado", {
|
|
50
|
+
userId: "123",
|
|
51
|
+
email: "user@example.com",
|
|
52
|
+
});
|
|
53
|
+
await logger.error("Error en el sistema", {
|
|
54
|
+
error: "Database connection failed",
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Con Múltiples Datasources
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { LoggerFactory } from "@jmlq/logger";
|
|
62
|
+
import { FileSystemDatasource } from "@jmlq/logger-plugin-fs";
|
|
63
|
+
import { MongoDatasource } from "@jmlq/logger-plugin-mongo";
|
|
64
|
+
|
|
65
|
+
const logger = LoggerFactory.create({
|
|
66
|
+
datasources: [
|
|
67
|
+
new FileSystemDatasource({ basePath: "./logs" }),
|
|
68
|
+
new MongoDatasource({ url: "mongodb://localhost:27017", dbName: "logs" }),
|
|
69
|
+
],
|
|
70
|
+
minLevel: LogLevel.INFO,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
await logger.warn("Latencia alta", { endpoint: "/api/users", duration: 850 });
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 🎯 Características Principales
|
|
77
|
+
|
|
78
|
+
### Niveles de Log
|
|
79
|
+
|
|
80
|
+
- `TRACE` (0) - Información muy detallada
|
|
81
|
+
- `DEBUG` (1) - Información de depuración
|
|
82
|
+
- `INFO` (2) - Información general
|
|
83
|
+
- `WARN` (3) - Advertencias
|
|
84
|
+
- `ERROR` (4) - Errores
|
|
85
|
+
- `FATAL` (5) - Errores críticos
|
|
86
|
+
|
|
87
|
+
### Enmascarado PII Automático
|
|
88
|
+
|
|
89
|
+
El logger detecta y enmascara automáticamente datos sensibles:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
await logger.info("Pago procesado", {
|
|
93
|
+
email: "user@example.com", // → user@[EMAIL]
|
|
94
|
+
card: "4111-1111-1111-1111", // → ****-****-****-****
|
|
95
|
+
password: "secret123", // → [REDACTED]
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Filtros y Consultas
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
// Obtener logs de errores de las últimas 24 horas
|
|
103
|
+
const errors = await logger.getLogs({
|
|
104
|
+
levelMin: LogLevel.ERROR,
|
|
105
|
+
since: Date.now() - 24 * 60 * 60 * 1000,
|
|
106
|
+
limit: 50,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Buscar logs que contengan "usuario"
|
|
110
|
+
const userLogs = await logger.getLogs({
|
|
111
|
+
query: "usuario",
|
|
112
|
+
limit: 100,
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## 🔧 Configuración con Variables de Entorno
|
|
117
|
+
|
|
118
|
+
```env
|
|
119
|
+
# Nivel mínimo de logs
|
|
120
|
+
LOG_LEVEL=info
|
|
121
|
+
|
|
122
|
+
# Filesystem
|
|
123
|
+
LOGGER_FS_PATH=./logs
|
|
124
|
+
|
|
125
|
+
# MongoDB
|
|
126
|
+
MONGO_URL=mongodb://localhost:27017
|
|
127
|
+
MONGO_DB_NAME=logs
|
|
128
|
+
|
|
129
|
+
# PostgreSQL
|
|
130
|
+
POSTGRES_URL=postgresql://user:pass@localhost:5432/logs
|
|
131
|
+
|
|
132
|
+
# PII Protection
|
|
133
|
+
LOGGER_PII_ENABLED=true
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## 📁 Ejemplos Prácticos
|
|
137
|
+
|
|
138
|
+
El proyecto incluye ejemplos completos en el directorio [`examples/`](examples/):
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# Ver todos los ejemplos disponibles
|
|
142
|
+
npm run example:help
|
|
143
|
+
|
|
144
|
+
# Ejecutar ejemplos específicos
|
|
145
|
+
npm run example:factories # LoggerFactory
|
|
146
|
+
npm run example:use-cases # SaveLog, GetLogs, FlushBuffers
|
|
147
|
+
npm run example:domain-services # PII, normalización
|
|
148
|
+
npm run example:all # Todos los ejemplos
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Ejemplo Express
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import express from "express";
|
|
155
|
+
import { LoggerFactory, LogLevel } from "@jmlq/logger";
|
|
156
|
+
|
|
157
|
+
const app = express();
|
|
158
|
+
const logger = LoggerFactory.create({
|
|
159
|
+
datasources: /* tu datasource */,
|
|
160
|
+
minLevel: LogLevel.INFO
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
app.use(async (req, res, next) => {
|
|
164
|
+
await logger.info("Request iniciado", {
|
|
165
|
+
method: req.method,
|
|
166
|
+
url: req.url,
|
|
167
|
+
ip: req.ip
|
|
168
|
+
});
|
|
169
|
+
next();
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
app.get("/users/:id", async (req, res) => {
|
|
173
|
+
try {
|
|
174
|
+
await logger.info("Obteniendo usuario", { userId: req.params.id });
|
|
175
|
+
// ... tu lógica
|
|
176
|
+
res.json({ user: data });
|
|
177
|
+
} catch (error) {
|
|
178
|
+
await logger.error("Error al obtener usuario", {
|
|
179
|
+
userId: req.params.id,
|
|
180
|
+
error: error.message
|
|
181
|
+
});
|
|
182
|
+
res.status(500).json({ error: "Internal server error" });
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Ejemplo NestJS
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
@Injectable()
|
|
191
|
+
export class AppService {
|
|
192
|
+
constructor(@Inject("LOGGER") private readonly logger: ILoggerService) {}
|
|
193
|
+
|
|
194
|
+
async createUser(userData: any) {
|
|
195
|
+
await this.logger.info("Creando usuario", { userData });
|
|
196
|
+
try {
|
|
197
|
+
// ... lógica
|
|
198
|
+
await this.logger.info("Usuario creado", { userId: result.id });
|
|
199
|
+
return result;
|
|
200
|
+
} catch (error) {
|
|
201
|
+
await this.logger.error("Error creando usuario", {
|
|
202
|
+
error: error.message,
|
|
203
|
+
});
|
|
204
|
+
throw error;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## 🏗️ Arquitectura
|
|
211
|
+
|
|
212
|
+
El paquete sigue **Arquitectura Limpia**:
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
src/
|
|
216
|
+
├─ domain/ # Reglas de negocio puras
|
|
217
|
+
│ ├─ entities/
|
|
218
|
+
│ ├─ value-objects/ # LogLevel
|
|
219
|
+
│ ├─ services/ # PiiRedactor, MessageNormalizer
|
|
220
|
+
│ ├─ ports/ # Interfaces/contratos
|
|
221
|
+
│ └─ types/
|
|
222
|
+
├─ application/ # Casos de uso
|
|
223
|
+
│ ├─ use-cases/ # SaveLog, GetLogs, FlushBuffers
|
|
224
|
+
│ └─ factory/ # LoggerFactory
|
|
225
|
+
└─ infrastructure/ # Implementaciones concretas
|
|
226
|
+
└─ services/ # DataSourceService (composite)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Casos de Uso Principales
|
|
230
|
+
|
|
231
|
+
- **[`SaveLogUseCase`](src/application/use-cases/save-log.use-case.ts)** - Guarda logs aplicando filtros de nivel y PII
|
|
232
|
+
- **[`GetLogsUseCase`](src/application/use-cases/get-logs.use-case.ts)** - Recupera logs con filtros
|
|
233
|
+
- **[`FlushBuffersUseCase`](src/application/use-cases/flush-buffers.use-case.ts)** - Vacía buffers de datasources
|
|
234
|
+
|
|
235
|
+
### Servicios de Dominio
|
|
236
|
+
|
|
237
|
+
- **[`PiiRedactor`](src/domain/services/pii-redactor.service.ts)** - Enmascara datos sensibles
|
|
238
|
+
- **[`MessageNormalizer`](src/domain/services/message-normalizer.service.ts)** - Normaliza mensajes de log
|
|
239
|
+
- **[`LogLevelService`](src/domain/services/log-level.service.ts)** - Maneja niveles de log
|
|
240
|
+
|
|
241
|
+
## 🔌 Plugins Disponibles
|
|
242
|
+
|
|
243
|
+
| Plugin | Descripción | NPM |
|
|
244
|
+
| -------------------------------- | -------------------------- | --------------------------------------------------------------- |
|
|
245
|
+
| `@jmlq/logger-plugin-fs` | Persistencia en archivos | [npm](https://npmjs.com/package/@jmlq/logger-plugin-fs) |
|
|
246
|
+
| `@jmlq/logger-plugin-mongo` | Persistencia en MongoDB | [npm](https://npmjs.com/package/@jmlq/logger-plugin-mongo) |
|
|
247
|
+
| `@jmlq/logger-plugin-postgresql` | Persistencia en PostgreSQL | [npm](https://npmjs.com/package/@jmlq/logger-plugin-postgresql) |
|
|
248
|
+
|
|
249
|
+
## 🧪 Testing
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
import { LoggerFactory, LogLevel } from "@jmlq/logger";
|
|
253
|
+
|
|
254
|
+
describe("Logger Tests", () => {
|
|
255
|
+
it("debe enmascarar PII correctamente", async () => {
|
|
256
|
+
const logs: any[] = [];
|
|
257
|
+
const mockDatasource = {
|
|
258
|
+
name: "mock",
|
|
259
|
+
async save(log: any) {
|
|
260
|
+
logs.push(log);
|
|
261
|
+
},
|
|
262
|
+
async find() {
|
|
263
|
+
return [];
|
|
264
|
+
},
|
|
265
|
+
async flush() {},
|
|
266
|
+
async dispose() {},
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
const logger = LoggerFactory.create({
|
|
270
|
+
datasources: mockDatasource,
|
|
271
|
+
redactorOptions: { enabled: true },
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
await logger.info("Usuario: user@example.com");
|
|
275
|
+
|
|
276
|
+
expect(logs[0].message).not.toContain("user@example.com");
|
|
277
|
+
expect(logs[0].message).toContain("[EMAIL]");
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## 🚨 Troubleshooting
|
|
283
|
+
|
|
284
|
+
**Error: No datasources válidos**
|
|
285
|
+
|
|
286
|
+
- Asegúrate de configurar al menos un datasource
|
|
287
|
+
- Verifica las variables de entorno
|
|
288
|
+
|
|
289
|
+
**MongoDB no conecta**
|
|
290
|
+
|
|
291
|
+
- Verifica la URL de conexión
|
|
292
|
+
- Incluye `authSource=admin` si usas usuarios root
|
|
293
|
+
|
|
294
|
+
**Alto uso de memoria**
|
|
295
|
+
|
|
296
|
+
- Implementa límites en las consultas
|
|
297
|
+
- Usa `flush()` periódicamente para vaciar buffers
|
|
298
|
+
|
|
299
|
+
## 📄 Más Información
|
|
300
|
+
|
|
301
|
+
- **[Arquitectura Detallada](./architecture.md)** - Documentación técnica completa
|
|
302
|
+
- **[Guía de Instalación](./install.md)** - Configuración paso a paso
|
|
303
|
+
- **[Ejemplos](./examples/)** - Códigos de ejemplo funcionales
|
|
304
|
+
|
|
305
|
+
## 📝 Licencia
|
|
306
|
+
|
|
307
|
+
MIT © Mauricio Lahuasi
|
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.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// 🧩 Ejemplo realista de cómo un cliente podría integrar DataSourceService
|
|
4
|
+
// ============================================================================
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DataSourceServiceExample = void 0;
|
|
7
|
+
const src_1 = require("src");
|
|
8
|
+
const infrastructure_1 = require("src/infrastructure");
|
|
9
|
+
/**
|
|
10
|
+
* InMemoryLogDatasource
|
|
11
|
+
*
|
|
12
|
+
* Implementación simple de ILogDatasource que almacena los logs en memoria.
|
|
13
|
+
* Útil para:
|
|
14
|
+
* - Tests
|
|
15
|
+
* - Ejemplos / demos
|
|
16
|
+
* - Entornos de desarrollo
|
|
17
|
+
*/
|
|
18
|
+
class InMemoryLogDatasource {
|
|
19
|
+
constructor() {
|
|
20
|
+
this.name = "in-memory";
|
|
21
|
+
this.logs = [];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Guarda un log en memoria.
|
|
25
|
+
* No aplica lógica especial, solo hace push al arreglo interno.
|
|
26
|
+
*/
|
|
27
|
+
async save(log) {
|
|
28
|
+
// Suponemos que ILogResponse es compatible con ILogProps.
|
|
29
|
+
// Si en tu dominio ILogResponse tiene campos extra (ej: id),
|
|
30
|
+
// aquí podrías generarlos.
|
|
31
|
+
this.logs.push(log);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Devuelve los logs almacenados en memoria.
|
|
35
|
+
* Por simplicidad, se ignora el filtro. Puedes adaptar esta parte cuando
|
|
36
|
+
* tengas definido el shape completo de IGetLogsFilterProps.
|
|
37
|
+
*/
|
|
38
|
+
async find(_filter) {
|
|
39
|
+
// Retornamos una copia para evitar mutación externa.
|
|
40
|
+
return [...this.logs];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Limpia todos los logs almacenados.
|
|
44
|
+
*/
|
|
45
|
+
async flush() {
|
|
46
|
+
this.logs.length = 0;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Libera recursos.
|
|
50
|
+
* En este caso es equivalente a flush(), pero queda listo
|
|
51
|
+
* por si en el futuro necesitas lógica adicional.
|
|
52
|
+
*/
|
|
53
|
+
async dispose() {
|
|
54
|
+
await this.flush();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* AppLoggerService
|
|
59
|
+
*
|
|
60
|
+
* Servicio de logging de la aplicación que:
|
|
61
|
+
* - Usa DataSourceService (composite) debajo.
|
|
62
|
+
* - Configura múltiples datasources.
|
|
63
|
+
* - Centraliza el manejo de errores del logger vía errorHandler.
|
|
64
|
+
*/
|
|
65
|
+
class AppLoggerService {
|
|
66
|
+
constructor() {
|
|
67
|
+
// 1️⃣ Definimos los datasources que usará la app
|
|
68
|
+
const datasources = [
|
|
69
|
+
new InMemoryLogDatasource(), // para debugging / tests / fallback
|
|
70
|
+
new HttpLogDatasource(// datasource custom del cliente
|
|
71
|
+
process.env.LOG_API_URL ?? "https://logs.my-api.com/events"),
|
|
72
|
+
];
|
|
73
|
+
// 2️⃣ Definimos un error handler centralizado para errores del logger
|
|
74
|
+
const errorHandler = (info) => {
|
|
75
|
+
// Aquí el cliente podría usar su propio logger de infra (pino, winston, etc).
|
|
76
|
+
// En este ejemplo usamos console.error por simplicidad.
|
|
77
|
+
// IMPORTANTE: este logger NO debe depender de @jmlq/logger para evitar ciclos.
|
|
78
|
+
console.error("[AppLoggerService] Error en datasource de logger", {
|
|
79
|
+
op: info.operation,
|
|
80
|
+
datasource: info.datasourceName,
|
|
81
|
+
error: info.reason,
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
// 3️⃣ Creamos el DataSourceService composite con los datasources y el handler
|
|
85
|
+
this.dataSourceService = new infrastructure_1.DataSourceService(datasources, errorHandler);
|
|
86
|
+
}
|
|
87
|
+
// ----------------------------------------------------------------------------
|
|
88
|
+
// API pública del logger de la app (lo que realmente usa el cliente)
|
|
89
|
+
// ----------------------------------------------------------------------------
|
|
90
|
+
async info(message, meta) {
|
|
91
|
+
await this.log(src_1.LogLevel.INFO, message, meta);
|
|
92
|
+
}
|
|
93
|
+
async warn(message, meta) {
|
|
94
|
+
await this.log(src_1.LogLevel.WARN, message, meta);
|
|
95
|
+
}
|
|
96
|
+
async error(message, meta) {
|
|
97
|
+
await this.log(src_1.LogLevel.ERROR, message, meta);
|
|
98
|
+
}
|
|
99
|
+
async debug(message, meta) {
|
|
100
|
+
await this.log(src_1.LogLevel.DEBUG, message, meta);
|
|
101
|
+
}
|
|
102
|
+
async log(level, message, meta) {
|
|
103
|
+
const log = {
|
|
104
|
+
level,
|
|
105
|
+
message,
|
|
106
|
+
timestamp: Date.now(),
|
|
107
|
+
meta,
|
|
108
|
+
};
|
|
109
|
+
await this.dataSourceService.save(log);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Métodos opcionales para flush/dispose (por ejemplo, en shutdown de la app).
|
|
113
|
+
*/
|
|
114
|
+
async flush() {
|
|
115
|
+
await this.dataSourceService.flush();
|
|
116
|
+
}
|
|
117
|
+
async dispose() {
|
|
118
|
+
await this.dataSourceService.dispose();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// ============================================================================
|
|
122
|
+
// 🌐 Ejemplo de datasource HTTP implementado por el cliente
|
|
123
|
+
// (no forma parte del core, lo crea el consumidor usando ILogDatasource)
|
|
124
|
+
// ============================================================================
|
|
125
|
+
class HttpLogDatasource {
|
|
126
|
+
constructor(endpoint) {
|
|
127
|
+
this.endpoint = endpoint;
|
|
128
|
+
this.name = "http";
|
|
129
|
+
}
|
|
130
|
+
async save(log) {
|
|
131
|
+
// Aquí el cliente puede usar fetch, axios, got, etc.
|
|
132
|
+
// Lo dejamos como pseudo-código para no acoplar dependencias reales.
|
|
133
|
+
const body = JSON.stringify(log);
|
|
134
|
+
await fetch(this.endpoint, {
|
|
135
|
+
method: "POST",
|
|
136
|
+
headers: { "Content-Type": "application/json" },
|
|
137
|
+
body,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// ============================================================================
|
|
142
|
+
// 🚀 Example runner: cómo el cliente lo usaría en su app
|
|
143
|
+
// ============================================================================
|
|
144
|
+
class DataSourceServiceExample {
|
|
145
|
+
static async Main() {
|
|
146
|
+
console.log("=== 🧩 Ejemplo REAL de uso: AppLoggerService sobre DataSourceService ===\n");
|
|
147
|
+
// 1️⃣ Crear instancia de logger de aplicación
|
|
148
|
+
const logger = new AppLoggerService();
|
|
149
|
+
// 2️⃣ Loguear eventos típicos de una app
|
|
150
|
+
console.log("📝 Enviando logs de ejemplo...\n");
|
|
151
|
+
await logger.info("Servidor iniciado", {
|
|
152
|
+
port: 3000,
|
|
153
|
+
env: process.env.NODE_ENV ?? "development",
|
|
154
|
+
});
|
|
155
|
+
await logger.info("Usuario autenticado", {
|
|
156
|
+
userId: "12345",
|
|
157
|
+
method: "password",
|
|
158
|
+
});
|
|
159
|
+
await logger.error("Error al procesar pedido", {
|
|
160
|
+
orderId: "ORD-999",
|
|
161
|
+
reason: "Stock insuficiente",
|
|
162
|
+
});
|
|
163
|
+
await logger.warn("Latencia alta detectada en /payments", {
|
|
164
|
+
p95_ms: 850,
|
|
165
|
+
});
|
|
166
|
+
console.log("✅ Logs enviados. Si algún datasource falla, el error handler los captura.\n");
|
|
167
|
+
// 3️⃣ Ejemplo de uso en shutdown de la app
|
|
168
|
+
console.log("🧹 Realizando flush() y dispose() del logger...\n");
|
|
169
|
+
await logger.flush();
|
|
170
|
+
await logger.dispose();
|
|
171
|
+
console.log("🏁 Ejemplo real completado.\n");
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
exports.DataSourceServiceExample = DataSourceServiceExample;
|