@jmlq/logger-plugin-fs 0.1.0-alpha.0 → 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 +229 -0
- package/architecture.md +426 -0
- package/dist/application/dto/index.d.ts +1 -0
- package/dist/application/dto/index.js +17 -0
- package/dist/application/dto/rotate-if-needed.request.d.ts +10 -0
- package/dist/application/dto/rotate-if-needed.request.js +2 -0
- package/dist/application/factory/create-fs-datasource.factory.d.ts +16 -0
- package/dist/application/factory/create-fs-datasource.factory.js +51 -0
- package/dist/application/factory/index.d.ts +1 -0
- package/dist/application/factory/index.js +17 -0
- package/dist/application/use-cases/append-log.use-case.d.ts +30 -0
- package/dist/application/use-cases/append-log.use-case.js +39 -0
- package/dist/application/use-cases/ensure-directory.use-case.d.ts +58 -0
- package/dist/application/use-cases/ensure-directory.use-case.js +64 -0
- package/dist/application/use-cases/find-logs-use-case.d.ts +17 -0
- package/dist/application/use-cases/find-logs-use-case.js +64 -0
- package/dist/application/use-cases/index.d.ts +5 -0
- package/dist/application/use-cases/index.js +21 -0
- package/dist/application/use-cases/persist-log.use-case.d.ts +96 -0
- package/dist/application/use-cases/persist-log.use-case.js +105 -0
- package/dist/application/use-cases/rotate-if-needed.use-case.d.ts +55 -0
- package/dist/application/use-cases/rotate-if-needed.use-case.js +61 -0
- package/dist/domain/model/index.d.ts +1 -0
- package/dist/domain/model/index.js +17 -0
- package/dist/domain/model/log-entry.model.d.ts +8 -0
- package/dist/domain/model/log-entry.model.js +2 -0
- package/dist/domain/ports/file/file-path.port.d.ts +38 -0
- package/dist/domain/ports/file/file-path.port.js +2 -0
- package/dist/domain/ports/file/file-rotator.port.d.ts +42 -0
- package/dist/domain/ports/file/file-rotator.port.js +2 -0
- package/dist/domain/ports/file/index.d.ts +2 -0
- package/dist/domain/ports/file/index.js +18 -0
- package/dist/domain/ports/file/log-stream-writer.port.d.ts +70 -0
- package/dist/domain/ports/file/log-stream-writer.port.js +2 -0
- package/dist/domain/ports/filesystem-provider.port.d.ts +61 -0
- package/dist/domain/ports/filesystem-provider.port.js +2 -0
- package/dist/domain/ports/index.d.ts +5 -0
- package/dist/domain/ports/index.js +21 -0
- package/dist/domain/ports/logs/find/index.d.ts +2 -0
- package/dist/domain/ports/logs/find/index.js +18 -0
- package/dist/domain/ports/logs/find/log-file-line-reader.port.d.ts +3 -0
- package/dist/domain/ports/logs/find/log-file-line-reader.port.js +2 -0
- package/dist/domain/ports/logs/find/log-file-numerator.port.d.ts +3 -0
- package/dist/domain/ports/logs/find/log-file-numerator.port.js +2 -0
- package/dist/domain/ports/logs/index.d.ts +2 -0
- package/dist/domain/ports/logs/index.js +18 -0
- package/dist/domain/ports/logs/log-datasource.port.d.ts +10 -0
- package/dist/domain/ports/logs/log-datasource.port.js +2 -0
- package/dist/domain/ports/system-clock.port.d.ts +8 -0
- package/dist/domain/ports/system-clock.port.js +2 -0
- package/dist/domain/request/index.d.ts +2 -0
- package/dist/domain/request/index.js +18 -0
- package/dist/domain/request/log-filter.request.d.ts +9 -0
- package/dist/domain/request/log-filter.request.js +2 -0
- package/dist/domain/request/save-log.request.d.ts +7 -0
- package/dist/domain/request/save-log.request.js +2 -0
- package/dist/domain/response/index.d.ts +1 -0
- package/dist/domain/response/index.js +17 -0
- package/dist/domain/response/log.response.d.ts +8 -0
- package/dist/domain/response/log.response.js +2 -0
- package/dist/domain/types/fs-rotation-by.type.d.ts +8 -0
- package/dist/domain/types/fs-rotation-by.type.js +2 -0
- package/dist/domain/types/index.d.ts +1 -0
- package/dist/domain/types/index.js +17 -0
- package/dist/domain/value-objects/file-name-pattern.vo.d.ts +36 -0
- package/dist/domain/value-objects/file-name-pattern.vo.js +53 -0
- package/dist/domain/value-objects/file-path.vo.d.ts +91 -0
- package/dist/domain/value-objects/file-path.vo.js +100 -0
- package/dist/domain/value-objects/file-rotation-policy.vo.d.ts +51 -0
- package/dist/domain/value-objects/file-rotation-policy.vo.js +76 -0
- package/dist/domain/value-objects/file-size.vo.d.ts +75 -0
- package/dist/domain/value-objects/file-size.vo.js +114 -0
- package/dist/domain/value-objects/index.d.ts +5 -0
- package/dist/domain/value-objects/index.js +21 -0
- package/dist/domain/value-objects/log-level.vo.d.ts +8 -0
- package/dist/domain/value-objects/log-level.vo.js +13 -0
- package/dist/index.d.ts +3 -11
- package/dist/index.js +10 -61
- package/dist/infrastructure/adapters/file-rotator.adapter.d.ts +79 -0
- package/dist/infrastructure/adapters/file-rotator.adapter.js +171 -0
- package/dist/infrastructure/adapters/fileSystem-datasource.adapter.d.ts +26 -0
- package/dist/infrastructure/adapters/fileSystem-datasource.adapter.js +45 -0
- package/dist/infrastructure/adapters/filesystem-log-file-enumerator.adapter.d.ts +6 -0
- package/dist/infrastructure/adapters/filesystem-log-file-enumerator.adapter.js +54 -0
- package/dist/infrastructure/adapters/filesystem-log-file-line-reader.adapter.d.ts +4 -0
- package/dist/infrastructure/adapters/filesystem-log-file-line-reader.adapter.js +53 -0
- package/dist/infrastructure/adapters/filesystem-provider.adapter.d.ts +122 -0
- package/dist/infrastructure/adapters/filesystem-provider.adapter.js +182 -0
- package/dist/infrastructure/adapters/index.d.ts +8 -0
- package/dist/infrastructure/adapters/index.js +24 -0
- package/dist/infrastructure/adapters/log-stream-writer.adapter.d.ts +80 -0
- package/dist/infrastructure/adapters/log-stream-writer.adapter.js +163 -0
- package/dist/infrastructure/adapters/system-clock.adapter.d.ts +25 -0
- package/dist/infrastructure/adapters/system-clock.adapter.js +30 -0
- package/dist/infrastructure/adapters/system-file-path.adapter.d.ts +47 -0
- package/dist/infrastructure/adapters/system-file-path.adapter.js +141 -0
- package/dist/infrastructure/errors/file-operation.error.d.ts +28 -0
- package/dist/infrastructure/errors/file-operation.error.js +54 -0
- package/dist/infrastructure/errors/index.d.ts +1 -0
- package/dist/infrastructure/errors/index.js +17 -0
- package/dist/infrastructure/errors/types/file-operation-error-options.type.d.ts +8 -0
- package/dist/infrastructure/errors/types/file-operation-error-options.type.js +2 -0
- package/dist/infrastructure/errors/types/file-operation.type.d.ts +1 -0
- package/dist/infrastructure/errors/types/file-operation.type.js +2 -0
- package/dist/infrastructure/errors/types/fs-error-scope.type.d.ts +1 -0
- package/dist/infrastructure/errors/types/fs-error-scope.type.js +2 -0
- package/dist/infrastructure/errors/types/index.d.ts +3 -0
- package/dist/infrastructure/errors/types/index.js +19 -0
- package/dist/infrastructure/filesystem/index.d.ts +1 -0
- package/dist/infrastructure/filesystem/index.js +17 -0
- package/dist/infrastructure/filesystem/types/filesystem-datasource-options.type.d.ts +45 -0
- package/dist/infrastructure/filesystem/types/filesystem-datasource-options.type.js +2 -0
- package/dist/infrastructure/filesystem/types/filesystem-rotation.type.d.ts +12 -0
- package/dist/infrastructure/filesystem/types/filesystem-rotation.type.js +2 -0
- package/dist/infrastructure/filesystem/types/index.d.ts +2 -0
- package/dist/infrastructure/filesystem/types/index.js +18 -0
- package/install.md +520 -0
- package/package.json +40 -12
package/install.md
ADDED
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
# Instalación y Configuración - @jmlq/logger-plugin-fs
|
|
2
|
+
|
|
3
|
+
## Introducción Técnica
|
|
4
|
+
|
|
5
|
+
`@jmlq/logger-plugin-fs` es un plugin para el sistema de logging `@jmlq/logger` que proporciona persistencia en sistema de archivos con capacidades avanzadas de rotación. Implementa Clean Architecture y está diseñado para aplicaciones Node.js que requieren logging persistente con gestión automática de archivos.
|
|
6
|
+
|
|
7
|
+
El plugin se integra como un datasource del logger principal, permitiendo escribir logs en archivos con políticas de rotación configurables (diaria, por tamaño, o sin rotación). Incluye funcionalidades como creación automática de directorios, serialización personalizable y callbacks para eventos de rotación.
|
|
8
|
+
|
|
9
|
+
## Instalación
|
|
10
|
+
|
|
11
|
+
### Dependencias Requeridas
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @jmlq/logger @jmlq/logger-plugin-fs
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Dependencias
|
|
18
|
+
|
|
19
|
+
El plugin requiere como peer dependency:
|
|
20
|
+
|
|
21
|
+
- `@jmlq/logger` >= 0.1.0-alpha.12
|
|
22
|
+
|
|
23
|
+
## Configuración del FileSystemDatasource
|
|
24
|
+
|
|
25
|
+
### Factory Principal
|
|
26
|
+
|
|
27
|
+
El plugin proporciona la función `createFsDatasource` que actúa como factory principal:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { createFsDatasource } from '@jmlq/logger-plugin-fs';
|
|
31
|
+
import { IFilesystemDatasourceOptions } from '@jmlq/logger-plugin-fs';
|
|
32
|
+
|
|
33
|
+
const datasource = createFsDatasource(options: IFilesystemDatasourceOptions);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Parámetros de Configuración
|
|
37
|
+
|
|
38
|
+
#### IFilesystemDatasourceOptions
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
interface IFilesystemDatasourceOptions {
|
|
42
|
+
basePath: string; // OBLIGATORIO
|
|
43
|
+
mkdir?: boolean; // Opcional, default: undefined
|
|
44
|
+
fileNamePattern?: string; // Opcional, default: "app-{yyyy}{MM}{dd}.log"
|
|
45
|
+
rotation?: IFileRotationConfig; // Opcional
|
|
46
|
+
serializer?: IFsSerializer; // Opcional
|
|
47
|
+
onRotate?: (oldPath: FilePath, newPath: FilePath) => void | Promise<void>;
|
|
48
|
+
onError?: (error: Error) => void | Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
#### Descripción de Parámetros
|
|
53
|
+
|
|
54
|
+
- **`basePath`** (string): Directorio base donde se crearán los archivos de log. Es el único parámetro obligatorio.
|
|
55
|
+
|
|
56
|
+
- **`mkdir`** (boolean, opcional): Si es `true`, crea automáticamente el directorio `basePath` usando `fs.mkdir({ recursive: true })` si no existe.
|
|
57
|
+
|
|
58
|
+
- **`fileNamePattern`** (string, opcional): Patrón para nombres de archivo. Default: `"app-{yyyy}{MM}{dd}.log"`. Admite placeholders:
|
|
59
|
+
|
|
60
|
+
- `{yyyy}` - Año de 4 dígitos
|
|
61
|
+
- `{MM}` - Mes de 2 dígitos (01-12)
|
|
62
|
+
- `{dd}` - Día de 2 dígitos (01-31)
|
|
63
|
+
|
|
64
|
+
- **`rotation`** (IFileRotationConfig, opcional): Configuración de política de rotación.
|
|
65
|
+
|
|
66
|
+
- **`serializer`** (IFsSerializer, opcional): Estrategia personalizada de serialización de logs a string.
|
|
67
|
+
|
|
68
|
+
- **`onRotate`** (función, opcional): Callback ejecutado cuando se rota un archivo. Útil para notificaciones o envío a servicios externos.
|
|
69
|
+
|
|
70
|
+
- **`onError`** (función, opcional): Callback centralizado para manejo de errores del datasource.
|
|
71
|
+
|
|
72
|
+
## Política de Rotación (RotationPolicy)
|
|
73
|
+
|
|
74
|
+
### Configuración IFileRotationConfig
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
interface IFileRotationConfig {
|
|
78
|
+
by: FsRotationBy; // "none" | "day" | "size"
|
|
79
|
+
maxSizeMB?: number; // Solo para by: "size"
|
|
80
|
+
maxFiles?: number; // Número máximo de archivos rotados a mantener
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Tipos de Rotación Soportados
|
|
85
|
+
|
|
86
|
+
#### 1. Sin Rotación (`"none"`)
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
const datasource = createFsDatasource({
|
|
90
|
+
basePath: "./logs",
|
|
91
|
+
rotation: {
|
|
92
|
+
by: "none",
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
El archivo crece indefinidamente sin rotación.
|
|
98
|
+
|
|
99
|
+
#### 2. Rotación Diaria (`"day"`)
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
const datasource = createFsDatasource({
|
|
103
|
+
basePath: "./logs",
|
|
104
|
+
fileNamePattern: "app-{yyyy}-{MM}-{dd}.log",
|
|
105
|
+
rotation: {
|
|
106
|
+
by: "day",
|
|
107
|
+
maxFiles: 7, // Mantener últimos 7 días
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Crea un archivo nuevo cada día basado en el patrón de fecha.
|
|
113
|
+
|
|
114
|
+
#### 3. Rotación por Tamaño (`"size"`)
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
const datasource = createFsDatasource({
|
|
118
|
+
basePath: "./logs",
|
|
119
|
+
rotation: {
|
|
120
|
+
by: "size",
|
|
121
|
+
maxSizeMB: 10, // OBLIGATORIO para rotación por tamaño
|
|
122
|
+
maxFiles: 5, // Mantener últimos 5 archivos
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Importante**: Para `by: "size"`, el parámetro `maxSizeMB` debe ser un número positivo.
|
|
128
|
+
|
|
129
|
+
## Serialización Personalizada
|
|
130
|
+
|
|
131
|
+
### Interface IFsSerializer
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
interface IFsSerializer {
|
|
135
|
+
serialize(entry: unknown): string;
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Implementación de Serializer Personalizado
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
const customSerializer: IFsSerializer = {
|
|
143
|
+
serialize(log: any): string {
|
|
144
|
+
// Ejemplo: formato personalizado con timestamp ISO
|
|
145
|
+
const timestamp = new Date(log.timestamp).toISOString();
|
|
146
|
+
return `[${timestamp}] ${log.level.toUpperCase()}: ${log.message}\n`;
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const datasource = createFsDatasource({
|
|
151
|
+
basePath: "./logs",
|
|
152
|
+
serializer: customSerializer,
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Ejemplos Técnicos Completos
|
|
157
|
+
|
|
158
|
+
### Configuración Básica
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { createFsDatasource } from "@jmlq/logger-plugin-fs";
|
|
162
|
+
import { LoggerFactory } from "@jmlq/logger";
|
|
163
|
+
|
|
164
|
+
// Crear datasource con configuración mínima
|
|
165
|
+
const fsDatasource = createFsDatasource({
|
|
166
|
+
basePath: "./logs",
|
|
167
|
+
mkdir: true,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Integrar con LoggerFactory
|
|
171
|
+
const logger = LoggerFactory.create({
|
|
172
|
+
datasources: [fsDatasource],
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Uso básico
|
|
176
|
+
logger.info("Aplicación iniciada");
|
|
177
|
+
logger.error("Error de conexión a base de datos");
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Configuración con Rotación por Día y Callbacks
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import { createFsDatasource } from "@jmlq/logger-plugin-fs";
|
|
184
|
+
import { LoggerFactory } from "@jmlq/logger";
|
|
185
|
+
import { FilePath } from "@jmlq/logger-plugin-fs";
|
|
186
|
+
|
|
187
|
+
const fsDatasource = createFsDatasource({
|
|
188
|
+
basePath: "./logs/production",
|
|
189
|
+
fileNamePattern: "app-{yyyy}-{MM}-{dd}.log",
|
|
190
|
+
mkdir: true,
|
|
191
|
+
rotation: {
|
|
192
|
+
by: "day",
|
|
193
|
+
maxFiles: 30, // Mantener logs de últimos 30 días
|
|
194
|
+
},
|
|
195
|
+
serializer: {
|
|
196
|
+
serialize(log: any): string {
|
|
197
|
+
return (
|
|
198
|
+
JSON.stringify({
|
|
199
|
+
timestamp: new Date(log.timestamp).toISOString(),
|
|
200
|
+
level: log.level,
|
|
201
|
+
message: log.message,
|
|
202
|
+
...log.extra,
|
|
203
|
+
}) + "\n"
|
|
204
|
+
);
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
onRotate: async (oldPath: FilePath, newPath: FilePath) => {
|
|
208
|
+
console.log(
|
|
209
|
+
`Log rotado: ${oldPath.absolutePath} → ${newPath.absolutePath}`
|
|
210
|
+
);
|
|
211
|
+
// Aquí podrías enviar el archivo a S3, comprimir, etc.
|
|
212
|
+
},
|
|
213
|
+
onError: async (error: Error) => {
|
|
214
|
+
console.error("Error en filesystem datasource:", error.message);
|
|
215
|
+
// Enviar métricas de error, notificar administradores, etc.
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const logger = LoggerFactory.create({
|
|
220
|
+
datasources: [fsDatasource],
|
|
221
|
+
});
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Configuración con Rotación por Tamaño
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
import { createFsDatasource } from "@jmlq/logger-plugin-fs";
|
|
228
|
+
import { LoggerFactory } from "@jmlq/logger";
|
|
229
|
+
|
|
230
|
+
const fsDatasource = createFsDatasource({
|
|
231
|
+
basePath: "./logs/high-volume",
|
|
232
|
+
fileNamePattern: "app.log",
|
|
233
|
+
mkdir: true,
|
|
234
|
+
rotation: {
|
|
235
|
+
by: "size",
|
|
236
|
+
maxSizeMB: 50, // Rotar cuando el archivo alcance 50MB
|
|
237
|
+
maxFiles: 10, // Mantener últimos 10 archivos rotados
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
const logger = LoggerFactory.create({
|
|
242
|
+
datasources: [fsDatasource],
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// Para aplicaciones con alto volumen de logs
|
|
246
|
+
for (let i = 0; i < 10000; i++) {
|
|
247
|
+
logger.debug(`Procesando registro ${i}`, {
|
|
248
|
+
userId: i,
|
|
249
|
+
operation: "bulk-process",
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Forzar escritura al archivo
|
|
254
|
+
await fsDatasource.flush();
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Uso en Frameworks
|
|
258
|
+
|
|
259
|
+
### Integración con Express
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
import express from "express";
|
|
263
|
+
import { createFsDatasource } from "@jmlq/logger-plugin-fs";
|
|
264
|
+
import { LoggerFactory, LogLevel } from "@jmlq/logger";
|
|
265
|
+
|
|
266
|
+
// Configurar datasource para Express
|
|
267
|
+
const fsDatasource = createFsDatasource({
|
|
268
|
+
basePath: "./logs/express",
|
|
269
|
+
fileNamePattern: "express-{yyyy}-{MM}-{dd}.log",
|
|
270
|
+
mkdir: true,
|
|
271
|
+
rotation: {
|
|
272
|
+
by: "day",
|
|
273
|
+
maxFiles: 15,
|
|
274
|
+
},
|
|
275
|
+
serializer: {
|
|
276
|
+
serialize(log: any): string {
|
|
277
|
+
return `${new Date(log.timestamp).toISOString()} [${log.level}] ${
|
|
278
|
+
log.message
|
|
279
|
+
}\n`;
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
const logger = LoggerFactory.create({
|
|
285
|
+
datasources: [fsDatasource],
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
const app = express();
|
|
289
|
+
|
|
290
|
+
// Middleware de logging
|
|
291
|
+
app.use((req, res, next) => {
|
|
292
|
+
logger.info(`${req.method} ${req.path}`, {
|
|
293
|
+
ip: req.ip,
|
|
294
|
+
userAgent: req.get("User-Agent"),
|
|
295
|
+
});
|
|
296
|
+
next();
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// Manejo de errores con logging
|
|
300
|
+
app.use(
|
|
301
|
+
(
|
|
302
|
+
err: Error,
|
|
303
|
+
req: express.Request,
|
|
304
|
+
res: express.Response,
|
|
305
|
+
next: express.NextFunction
|
|
306
|
+
) => {
|
|
307
|
+
logger.error("Error en aplicación Express", {
|
|
308
|
+
error: err.message,
|
|
309
|
+
stack: err.stack,
|
|
310
|
+
url: req.url,
|
|
311
|
+
method: req.method,
|
|
312
|
+
});
|
|
313
|
+
res.status(500).json({ error: "Internal Server Error" });
|
|
314
|
+
}
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
app.listen(3000, () => {
|
|
318
|
+
logger.info("Servidor Express iniciado en puerto 3000");
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// Cerrar correctamente el datasource al terminar la aplicación
|
|
322
|
+
process.on("SIGINT", async () => {
|
|
323
|
+
logger.info("Cerrando aplicación...");
|
|
324
|
+
await fsDatasource.flush();
|
|
325
|
+
await fsDatasource.dispose();
|
|
326
|
+
process.exit(0);
|
|
327
|
+
});
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Integración con NestJS
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
import { Injectable, Module, OnModuleDestroy } from "@nestjs/common";
|
|
334
|
+
import { createFsDatasource } from "@jmlq/logger-plugin-fs";
|
|
335
|
+
import { LoggerFactory, ILogDatasource } from "@jmlq/logger";
|
|
336
|
+
|
|
337
|
+
@Injectable()
|
|
338
|
+
export class LoggingService implements OnModuleDestroy {
|
|
339
|
+
private readonly fsDatasource: ILogDatasource;
|
|
340
|
+
private readonly logger: any;
|
|
341
|
+
|
|
342
|
+
constructor() {
|
|
343
|
+
this.fsDatasource = createFsDatasource({
|
|
344
|
+
basePath: "./logs/nestjs",
|
|
345
|
+
fileNamePattern: "nest-{yyyy}-{MM}-{dd}.log",
|
|
346
|
+
mkdir: true,
|
|
347
|
+
rotation: {
|
|
348
|
+
by: "day",
|
|
349
|
+
maxFiles: 30,
|
|
350
|
+
},
|
|
351
|
+
serializer: {
|
|
352
|
+
serialize(log: any): string {
|
|
353
|
+
return (
|
|
354
|
+
JSON.stringify({
|
|
355
|
+
timestamp: new Date(log.timestamp).toISOString(),
|
|
356
|
+
level: log.level,
|
|
357
|
+
message: log.message,
|
|
358
|
+
context: log.context || "Application",
|
|
359
|
+
...log.extra,
|
|
360
|
+
}) + "\n"
|
|
361
|
+
);
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
onError: async (error: Error) => {
|
|
365
|
+
console.error("[FS Logger Plugin]", error.message);
|
|
366
|
+
},
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
this.logger = LoggerFactory.create({
|
|
370
|
+
datasources: [this.fsDatasource],
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
log(message: string, context?: string, extra?: any) {
|
|
375
|
+
this.logger.info(message, { context, ...extra });
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
error(message: string, trace?: string, context?: string, extra?: any) {
|
|
379
|
+
this.logger.error(message, { trace, context, ...extra });
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
warn(message: string, context?: string, extra?: any) {
|
|
383
|
+
this.logger.warn(message, { context, ...extra });
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
debug(message: string, context?: string, extra?: any) {
|
|
387
|
+
this.logger.debug(message, { context, ...extra });
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
async onModuleDestroy() {
|
|
391
|
+
await this.fsDatasource.flush();
|
|
392
|
+
await this.fsDatasource.dispose();
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
@Module({
|
|
397
|
+
providers: [LoggingService],
|
|
398
|
+
exports: [LoggingService],
|
|
399
|
+
})
|
|
400
|
+
export class LoggingModule {}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
## Variables de Entorno
|
|
404
|
+
|
|
405
|
+
El plugin no maneja variables de entorno directamente. Para usarlas, mapéalas manualmente en la configuración:
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
import { createFsDatasource } from "@jmlq/logger-plugin-fs";
|
|
409
|
+
|
|
410
|
+
const fsDatasource = createFsDatasource({
|
|
411
|
+
basePath: process.env.LOG_DIR || "./logs",
|
|
412
|
+
mkdir: process.env.NODE_ENV !== "development",
|
|
413
|
+
fileNamePattern: process.env.LOG_FILE_PATTERN || "app-{yyyy}-{MM}-{dd}.log",
|
|
414
|
+
rotation: {
|
|
415
|
+
by: (process.env.LOG_ROTATION_TYPE as any) || "day",
|
|
416
|
+
maxSizeMB: process.env.LOG_MAX_SIZE_MB
|
|
417
|
+
? parseInt(process.env.LOG_MAX_SIZE_MB)
|
|
418
|
+
: undefined,
|
|
419
|
+
maxFiles: process.env.LOG_MAX_FILES
|
|
420
|
+
? parseInt(process.env.LOG_MAX_FILES)
|
|
421
|
+
: 7,
|
|
422
|
+
},
|
|
423
|
+
});
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Ejemplo de archivo `.env`:
|
|
427
|
+
|
|
428
|
+
```env
|
|
429
|
+
LOG_DIR=./logs/production
|
|
430
|
+
LOG_FILE_PATTERN=myapp-{yyyy}-{MM}-{dd}.log
|
|
431
|
+
LOG_ROTATION_TYPE=day
|
|
432
|
+
LOG_MAX_FILES=30
|
|
433
|
+
# Para rotación por tamaño:
|
|
434
|
+
# LOG_ROTATION_TYPE=size
|
|
435
|
+
# LOG_MAX_SIZE_MB=100
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
## Consideraciones Técnicas
|
|
439
|
+
|
|
440
|
+
### Permisos del Sistema de Archivos
|
|
441
|
+
|
|
442
|
+
- Asegúrate de que el proceso Node.js tenga permisos de escritura en el directorio `basePath`.
|
|
443
|
+
- Para producción, considera usar directorios como `/var/log/tu-app` en sistemas Unix.
|
|
444
|
+
- En contenedores Docker, monta volúmenes para persistir los logs:
|
|
445
|
+
|
|
446
|
+
```dockerfile
|
|
447
|
+
VOLUME ["/app/logs"]
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### Gestión de Recursos
|
|
451
|
+
|
|
452
|
+
#### Flush Explícito
|
|
453
|
+
|
|
454
|
+
```typescript
|
|
455
|
+
// Forzar escritura de buffers pendientes
|
|
456
|
+
await datasource.flush();
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
#### Cierre Correcto
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
// Cerrar streams y liberar recursos
|
|
463
|
+
await datasource.dispose();
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
#### Manejo de Shutdown Graceful
|
|
467
|
+
|
|
468
|
+
```typescript
|
|
469
|
+
process.on("SIGTERM", async () => {
|
|
470
|
+
await datasource.flush();
|
|
471
|
+
await datasource.dispose();
|
|
472
|
+
process.exit(0);
|
|
473
|
+
});
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### Rendimiento y Recomendaciones
|
|
477
|
+
|
|
478
|
+
- **Rotación por tamaño**: Más eficiente para aplicaciones con volumen variable de logs.
|
|
479
|
+
- **Rotación diaria**: Mejor para aplicaciones con logs predecibles y análisis temporal.
|
|
480
|
+
- **Serializer personalizado**: Optimiza el formato según tus necesidades de análisis posterior.
|
|
481
|
+
- **Callbacks `onRotate`**: Úsalos para automatizar tareas como compresión o envío a servicios externos.
|
|
482
|
+
- **Callback `onError`**: Implementa logging secundario o métricas de monitoreo.
|
|
483
|
+
|
|
484
|
+
### Limitaciones Conocidas
|
|
485
|
+
|
|
486
|
+
- El plugin funciona únicamente con Node.js (no browser).
|
|
487
|
+
- La rotación por tamaño requiere especificar `maxSizeMB` obligatoriamente.
|
|
488
|
+
- Los placeholders en `fileNamePattern` están limitados a: `{yyyy}`, `{MM}`, `{dd}`.
|
|
489
|
+
- La rotación se basa en la fecha del sistema local.
|
|
490
|
+
|
|
491
|
+
## Troubleshooting
|
|
492
|
+
|
|
493
|
+
### Error: "maxSizeMB must be positive for size rotation"
|
|
494
|
+
|
|
495
|
+
Especifica `maxSizeMB` mayor a 0 cuando uses `rotation.by = "size"`:
|
|
496
|
+
|
|
497
|
+
```typescript
|
|
498
|
+
rotation: {
|
|
499
|
+
by: 'size',
|
|
500
|
+
maxSizeMB: 10 // Obligatorio y > 0
|
|
501
|
+
}
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
### Error: Permisos insuficientes
|
|
505
|
+
|
|
506
|
+
Verifica permisos del directorio:
|
|
507
|
+
|
|
508
|
+
```bash
|
|
509
|
+
chmod 755 /ruta/a/logs
|
|
510
|
+
chown node:node /ruta/a/logs
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
### Logs no aparecen inmediatamente
|
|
514
|
+
|
|
515
|
+
Llama `flush()` para forzar escritura:
|
|
516
|
+
|
|
517
|
+
```typescript
|
|
518
|
+
logger.info("Mensaje importante");
|
|
519
|
+
await datasource.flush(); // Fuerza escritura inmediata
|
|
520
|
+
```
|
package/package.json
CHANGED
|
@@ -1,22 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jmlq/logger-plugin-fs",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
3
|
+
"description": "Filesystem plugin for JMLQ Logger implementing Clean Architecture principles.",
|
|
4
|
+
"version": "0.1.0-alpha.10",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
-
"files": [
|
|
8
|
-
"dist"
|
|
9
|
-
],
|
|
10
7
|
"scripts": {
|
|
11
|
-
"
|
|
12
|
-
"
|
|
8
|
+
"dev": "rimraf dist && mkdir dist && tsc -p tsconfig.json",
|
|
9
|
+
"build": "rimraf dist && mkdir dist && tsc -p tsconfig.build.json",
|
|
10
|
+
"prepublishOnly": "npm run build",
|
|
11
|
+
"test": "jest --passWithNoTests",
|
|
12
|
+
"test:watch": "jest --watch",
|
|
13
|
+
"test:coverage": "jest --coverage",
|
|
14
|
+
"example:help": "tsx examples/index.example.ts help",
|
|
15
|
+
"example:all": "tsx examples/index.example.ts",
|
|
16
|
+
"example:value-objects": "tsx examples/index.example.ts value-objects",
|
|
17
|
+
"example:infrastructure-adapters": "tsx examples/index.example.ts infrastructure-adapters",
|
|
18
|
+
"example:application-use-cases": "tsx examples/index.example.ts application-use-cases",
|
|
19
|
+
"example:application-services": "tsx examples/index.example.ts application-services",
|
|
20
|
+
"example:application-factories": "tsx examples/index.example.ts application-factories"
|
|
13
21
|
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"logger",
|
|
24
|
+
"filesystem",
|
|
25
|
+
"clean-architecture",
|
|
26
|
+
"typescript"
|
|
27
|
+
],
|
|
28
|
+
"author": "MLahuasi",
|
|
29
|
+
"license": "MIT",
|
|
14
30
|
"devDependencies": {
|
|
15
|
-
"@
|
|
16
|
-
"
|
|
17
|
-
"
|
|
31
|
+
"@swc/core": "^1.3.95",
|
|
32
|
+
"@swc/jest": "^0.2.29",
|
|
33
|
+
"@types/bcryptjs": "^2.4.5",
|
|
34
|
+
"@types/jest": "^29.5.8",
|
|
35
|
+
"@types/node": "^20.8.10",
|
|
36
|
+
"jest": "^29.7.0",
|
|
37
|
+
"rimraf": "^6.1.2",
|
|
38
|
+
"tsx": "^4.1.4",
|
|
39
|
+
"typescript": "^5.2.2"
|
|
18
40
|
},
|
|
19
|
-
"
|
|
20
|
-
"
|
|
41
|
+
"files": [
|
|
42
|
+
"dist",
|
|
43
|
+
"README.md",
|
|
44
|
+
"architecture.md",
|
|
45
|
+
"install.md"
|
|
46
|
+
],
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@jmlq/logger": "^0.1.0-alpha.20"
|
|
21
49
|
}
|
|
22
50
|
}
|