@jmlq/logger-plugin-fs 0.0.1-beta.1
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.es.md +224 -0
- package/README.md +224 -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/types/filesystem-datasource-options.type.d.ts +45 -0
- package/dist/application/types/filesystem-datasource-options.type.js +2 -0
- package/dist/application/types/index.d.ts +1 -0
- package/dist/application/types/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 +4 -0
- package/dist/index.js +12 -0
- 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-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 +1 -0
- package/dist/infrastructure/filesystem/types/index.js +17 -0
- package/package.json +46 -0
package/README.es.md
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# @jmlq/logger-plugin-fs 🧩
|
|
2
|
+
|
|
3
|
+
## 🎯 Objetivo
|
|
4
|
+
|
|
5
|
+
`@jmlq/logger-plugin-fs` es el plugin de persistencia en filesystem para `@jmlq/logger`.
|
|
6
|
+
Su responsabilidad es construir un `ILogDatasource` compatible con el core del logger para:
|
|
7
|
+
|
|
8
|
+
- escribir logs en archivos,
|
|
9
|
+
- rotar archivos según política configurada,
|
|
10
|
+
- buscar logs históricos desde archivos `.log`,
|
|
11
|
+
- exponer `flush()` sobre el writer del datasource.
|
|
12
|
+
|
|
13
|
+
El punto de entrada recomendado del paquete es `createFsDatasource(...)`.
|
|
14
|
+
|
|
15
|
+
## ⭐ Importancia
|
|
16
|
+
|
|
17
|
+
Este plugin resuelve un escenario muy común en aplicaciones Node.js:
|
|
18
|
+
|
|
19
|
+
- persistencia local en disco,
|
|
20
|
+
- operación simple sin depender de MongoDB o PostgreSQL,
|
|
21
|
+
- trazabilidad por archivo diario o por tamaño,
|
|
22
|
+
- integración directa con `@jmlq/logger` sin acoplar el host a detalles de `fs`, `path` o streams.
|
|
23
|
+
|
|
24
|
+
Además, mantiene separación clara entre dominio, casos de uso y adaptadores de Node.js.
|
|
25
|
+
|
|
26
|
+
## 🏗️ Arquitectura (visión rápida)
|
|
27
|
+
|
|
28
|
+
- `createFsDatasource(...)` construye el grafo completo del plugin.
|
|
29
|
+
- El plugin usa value objects como `FileNamePattern` y `FileRotationPolicy`.
|
|
30
|
+
- La escritura real ocurre vía `LogStreamWriterAdapter`.
|
|
31
|
+
- La lectura histórica ocurre con `FileSystemLogFileEnumeratorAdapter` y `FileSystemLogFileLineReaderAdapter`.
|
|
32
|
+
- El adapter público que se entrega al core es `FsDatasourceAdapter`.
|
|
33
|
+
|
|
34
|
+
➡️ Ver detalle en: [architecture.md](./docs/es/architecture.md)
|
|
35
|
+
|
|
36
|
+
## 🔧 Implementación
|
|
37
|
+
|
|
38
|
+
### 5.1 Instalación
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm i @jmlq/logger @jmlq/logger-plugin-fs
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 5.2 Dependencias
|
|
45
|
+
|
|
46
|
+
Dependencia directa del plugin:
|
|
47
|
+
|
|
48
|
+
- `@jmlq/logger`
|
|
49
|
+
|
|
50
|
+
El plugin usa internamente APIs de Node.js para filesystem/streams, pero esas dependencias no se exponen como configuración del consumidor.
|
|
51
|
+
|
|
52
|
+
### 5.3 Quickstart (implementación rápida)
|
|
53
|
+
|
|
54
|
+
Uso directo del plugin:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { createLogger } from "@jmlq/logger";
|
|
58
|
+
import { createFsDatasource } from "@jmlq/logger-plugin-fs";
|
|
59
|
+
|
|
60
|
+
const fsDatasource = createFsDatasource({
|
|
61
|
+
basePath: "./logs",
|
|
62
|
+
fileNamePattern: "app-{yyyy}{MM}{dd}.log",
|
|
63
|
+
rotation: { by: "day" },
|
|
64
|
+
mkdir: true,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const logger = createLogger({
|
|
68
|
+
datasources: fsDatasource,
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
En una capa `infrastructure` del host, una implementación típica queda así:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import {
|
|
76
|
+
createFsDatasource,
|
|
77
|
+
type IFilesystemDatasourceOptions,
|
|
78
|
+
} from "@jmlq/logger-plugin-fs";
|
|
79
|
+
import type { ILogDatasource } from "@jmlq/logger";
|
|
80
|
+
|
|
81
|
+
export class FsAdapter {
|
|
82
|
+
private constructor(private readonly ds: ILogDatasource) {}
|
|
83
|
+
|
|
84
|
+
static create(opts: IFilesystemDatasourceOptions): FsAdapter | undefined {
|
|
85
|
+
try {
|
|
86
|
+
const ds = createFsDatasource(opts);
|
|
87
|
+
console.log("[logger] Conectado a FS para logs");
|
|
88
|
+
return new FsAdapter(ds);
|
|
89
|
+
} catch (e: any) {
|
|
90
|
+
console.warn("[logger] FS deshabilitado:", e?.message ?? e);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
get datasource(): ILogDatasource {
|
|
95
|
+
return this.ds;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 5.4 Variables de entorno (.env) 📦
|
|
101
|
+
|
|
102
|
+
El plugin no consume variables de entorno por sí mismo.
|
|
103
|
+
En el host, la configuración real puede resolverse desde `envs.logger`.
|
|
104
|
+
|
|
105
|
+
Ejemplo de consumo real en un bootstrap del logger:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
fs: envs.logger.LOGGER_FS_PATH
|
|
109
|
+
? {
|
|
110
|
+
basePath: envs.logger.LOGGER_FS_PATH,
|
|
111
|
+
fileNamePattern: "app-{yyyy}{MM}{dd}.log",
|
|
112
|
+
rotation: { by: "day" },
|
|
113
|
+
mkdir: true,
|
|
114
|
+
onRotate: (oldPath, newPath) => {
|
|
115
|
+
console.log(
|
|
116
|
+
` [Rotate] Rotación completada: ${oldPath.absolutePath} → ${newPath.absolutePath}`,
|
|
117
|
+
);
|
|
118
|
+
},
|
|
119
|
+
onError: (err) => {
|
|
120
|
+
console.error(" [Error Handler]", err.message);
|
|
121
|
+
},
|
|
122
|
+
}
|
|
123
|
+
: undefined,
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Variables usadas por ese host para este plugin:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
process.env.LOGGER_FS_PATH;
|
|
130
|
+
process.env.LOG_LEVEL;
|
|
131
|
+
process.env.LOGGER_PII_ENABLED;
|
|
132
|
+
process.env.LOGGER_PII_INCLUDE_DEFAULTS;
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### 5.5 Helpers y funcionalidades clave
|
|
136
|
+
|
|
137
|
+
#### `IFilesystemDatasourceOptions`
|
|
138
|
+
|
|
139
|
+
Configuración pública real del datasource:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
export interface IFilesystemDatasourceOptions {
|
|
143
|
+
basePath: string;
|
|
144
|
+
mkdir?: boolean;
|
|
145
|
+
fileNamePattern?: string;
|
|
146
|
+
rotation?: IFileSystemRotationConfig;
|
|
147
|
+
onRotate?: (oldPath: FilePath, newPath: FilePath) => void | Promise<void>;
|
|
148
|
+
onError?: (error: Error) => void | Promise<void>;
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
#### Rotación
|
|
153
|
+
|
|
154
|
+
El plugin soporta estas políticas:
|
|
155
|
+
|
|
156
|
+
- `none`
|
|
157
|
+
- `day`
|
|
158
|
+
- `size`
|
|
159
|
+
|
|
160
|
+
Ejemplo:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
rotation: { by: "day" }
|
|
164
|
+
rotation: { by: "size", maxSizeMB: 50, maxFiles: 10 }
|
|
165
|
+
rotation: { by: "none" }
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### Patrón de nombre de archivo
|
|
169
|
+
|
|
170
|
+
El plugin usa `FileNamePattern` y soporta tokens de fecha como:
|
|
171
|
+
|
|
172
|
+
- `{yyyy}`
|
|
173
|
+
- `{MM}`
|
|
174
|
+
- `{dd}`
|
|
175
|
+
|
|
176
|
+
Ejemplo:
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
fileNamePattern: "app-{yyyy}{MM}{dd}.log";
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
#### Hooks útiles
|
|
183
|
+
|
|
184
|
+
- `onRotate`: notificación después de la rotación
|
|
185
|
+
- `onError`: centraliza errores del datasource
|
|
186
|
+
|
|
187
|
+
#### Lectura histórica
|
|
188
|
+
|
|
189
|
+
El datasource también expone búsqueda de logs usando `find(...)`, apoyado en:
|
|
190
|
+
|
|
191
|
+
- enumeración de archivos `.log`,
|
|
192
|
+
- lectura línea por línea,
|
|
193
|
+
- filtrado por nivel, fechas y query textual.
|
|
194
|
+
|
|
195
|
+
### 5.7 Escenario actual
|
|
196
|
+
|
|
197
|
+
La integración documentada está orientada a Express y a un bootstrap de infraestructura similar al que ya usas con `@jmlq/logger`, pero el plugin se mantiene desacoplado del framework HTTP.
|
|
198
|
+
|
|
199
|
+
## ✅ Checklist (pasos rápidos)
|
|
200
|
+
|
|
201
|
+
- [Instalar](#51-instalación)
|
|
202
|
+
- [Crear el datasource con `createFsDatasource`](./docs/es/configuration.md#crear-el-datasource-con-createfsdatasource)
|
|
203
|
+
- [Configurar rotación y patrón de nombre](./docs/es/configuration.md#configuración-real-del-datasource)
|
|
204
|
+
- [Integrar el datasource en el bootstrap del logger](./docs/es/integration-express.md#bootstrap-del-logger-en-el-host)
|
|
205
|
+
- [Adjuntar logger a Express](./docs/es/integration-express.md#adjuntar-logger-al-request)
|
|
206
|
+
- [Revisar problemas comunes](./docs/es/troubleshooting.md)
|
|
207
|
+
|
|
208
|
+
## 📌 Menú
|
|
209
|
+
|
|
210
|
+
- [Arquitectura](./docs/es/architecture.md)
|
|
211
|
+
- [Configuración](./docs/es/configuration.md)
|
|
212
|
+
- [Integración Express](./docs/es/integration-express.md)
|
|
213
|
+
- [Troubleshooting](./docs/es/troubleshooting.md)
|
|
214
|
+
|
|
215
|
+
## 🔗 Referencias
|
|
216
|
+
|
|
217
|
+
- [`@jmlq/logger`](https://github.com/MLahuasi/jmlq-logger#readme)
|
|
218
|
+
- Plugins relacionados del ecosistema:
|
|
219
|
+
- [`@jmlq/logger-plugin-mongo`](https://github.com/MLahuasi/jmlq-logger-plugin-mongo#readme)
|
|
220
|
+
- [`@jmlq/logger-plugin-postgresql`](https://github.com/MLahuasi/jmlq-logger-plugin-postgresql#readme)
|
|
221
|
+
|
|
222
|
+
## ⬅️ 🌐 Ecosistema
|
|
223
|
+
|
|
224
|
+
- [`@jmlq`](https://github.com/MLahuasi/jmlq-ecosystem#readme)
|
package/README.md
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# @jmlq/logger-plugin-fs 🧩
|
|
2
|
+
|
|
3
|
+
## 🎯 Objective
|
|
4
|
+
|
|
5
|
+
`@jmlq/logger-plugin-fs` is the filesystem persistence plugin for `@jmlq/logger`.
|
|
6
|
+
Its responsibility is to build an `ILogDatasource` compatible with the logger core to:
|
|
7
|
+
|
|
8
|
+
- write logs to files,
|
|
9
|
+
- rotate files based on a configured policy,
|
|
10
|
+
- search historical logs from `.log` files,
|
|
11
|
+
- expose `flush()` over the datasource writer.
|
|
12
|
+
|
|
13
|
+
The recommended entry point of the package is `createFsDatasource(...)`.
|
|
14
|
+
|
|
15
|
+
## ⭐ Importance
|
|
16
|
+
|
|
17
|
+
This plugin solves a very common scenario in Node.js applications:
|
|
18
|
+
|
|
19
|
+
- local disk persistence,
|
|
20
|
+
- simple operation without depending on MongoDB or PostgreSQL,
|
|
21
|
+
- traceability by daily file or by size,
|
|
22
|
+
- direct integration with `@jmlq/logger` without coupling the host to `fs`, `path`, or streams details.
|
|
23
|
+
|
|
24
|
+
It also maintains a clear separation between domain, use cases, and Node.js adapters.
|
|
25
|
+
|
|
26
|
+
## 🏗️ Architecture (quick view)
|
|
27
|
+
|
|
28
|
+
- `createFsDatasource(...)` builds the full plugin graph.
|
|
29
|
+
- The plugin uses value objects such as `FileNamePattern` and `FileRotationPolicy`.
|
|
30
|
+
- Actual writing is performed via `LogStreamWriterAdapter`.
|
|
31
|
+
- Historical reading is handled by `FileSystemLogFileEnumeratorAdapter` and `FileSystemLogFileLineReaderAdapter`.
|
|
32
|
+
- The public adapter exposed to the core is `FsDatasourceAdapter`.
|
|
33
|
+
|
|
34
|
+
➡️ See details: [architecture.md](./docs/en/architecture.md)
|
|
35
|
+
|
|
36
|
+
## 🔧 Implementation
|
|
37
|
+
|
|
38
|
+
### 5.1 Installation
|
|
39
|
+
|
|
40
|
+
```bash id="q1c8rt"
|
|
41
|
+
npm i @jmlq/logger @jmlq/logger-plugin-fs
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 5.2 Dependencies
|
|
45
|
+
|
|
46
|
+
Direct dependency of the plugin:
|
|
47
|
+
|
|
48
|
+
- `@jmlq/logger`
|
|
49
|
+
|
|
50
|
+
The plugin internally uses Node.js APIs for filesystem/streams, but those dependencies are not exposed as configuration for the consumer.
|
|
51
|
+
|
|
52
|
+
### 5.3 Quickstart (rapid implementation)
|
|
53
|
+
|
|
54
|
+
Direct plugin usage:
|
|
55
|
+
|
|
56
|
+
```ts id="u8z3pw"
|
|
57
|
+
import { createLogger } from "@jmlq/logger";
|
|
58
|
+
import { createFsDatasource } from "@jmlq/logger-plugin-fs";
|
|
59
|
+
|
|
60
|
+
const fsDatasource = createFsDatasource({
|
|
61
|
+
basePath: "./logs",
|
|
62
|
+
fileNamePattern: "app-{yyyy}{MM}{dd}.log",
|
|
63
|
+
rotation: { by: "day" },
|
|
64
|
+
mkdir: true,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const logger = createLogger({
|
|
68
|
+
datasources: fsDatasource,
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
In a host `infrastructure` layer, a typical implementation looks like this:
|
|
73
|
+
|
|
74
|
+
```ts id="v5m2kl"
|
|
75
|
+
import {
|
|
76
|
+
createFsDatasource,
|
|
77
|
+
type IFilesystemDatasourceOptions,
|
|
78
|
+
} from "@jmlq/logger-plugin-fs";
|
|
79
|
+
import type { ILogDatasource } from "@jmlq/logger";
|
|
80
|
+
|
|
81
|
+
export class FsAdapter {
|
|
82
|
+
private constructor(private readonly ds: ILogDatasource) {}
|
|
83
|
+
|
|
84
|
+
static create(opts: IFilesystemDatasourceOptions): FsAdapter | undefined {
|
|
85
|
+
try {
|
|
86
|
+
const ds = createFsDatasource(opts);
|
|
87
|
+
console.log("[logger] Connected to FS for logs");
|
|
88
|
+
return new FsAdapter(ds);
|
|
89
|
+
} catch (e: any) {
|
|
90
|
+
console.warn("[logger] FS disabled:", e?.message ?? e);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
get datasource(): ILogDatasource {
|
|
95
|
+
return this.ds;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 5.4 Environment variables (.env) 📦
|
|
101
|
+
|
|
102
|
+
The plugin does not consume environment variables by itself.
|
|
103
|
+
In the host, the actual configuration can be resolved from `envs.logger`.
|
|
104
|
+
|
|
105
|
+
Example of real usage in a logger bootstrap:
|
|
106
|
+
|
|
107
|
+
```ts id="t3n9qx"
|
|
108
|
+
fs: envs.logger.LOGGER_FS_PATH
|
|
109
|
+
? {
|
|
110
|
+
basePath: envs.logger.LOGGER_FS_PATH,
|
|
111
|
+
fileNamePattern: "app-{yyyy}{MM}{dd}.log",
|
|
112
|
+
rotation: { by: "day" },
|
|
113
|
+
mkdir: true,
|
|
114
|
+
onRotate: (oldPath, newPath) => {
|
|
115
|
+
console.log(
|
|
116
|
+
` [Rotate] Rotation completed: ${oldPath.absolutePath} → ${newPath.absolutePath}`,
|
|
117
|
+
);
|
|
118
|
+
},
|
|
119
|
+
onError: (err) => {
|
|
120
|
+
console.error(" [Error Handler]", err.message);
|
|
121
|
+
},
|
|
122
|
+
}
|
|
123
|
+
: undefined,
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Variables used by that host for this plugin:
|
|
127
|
+
|
|
128
|
+
```ts id="x7q4yb"
|
|
129
|
+
process.env.LOGGER_FS_PATH;
|
|
130
|
+
process.env.LOG_LEVEL;
|
|
131
|
+
process.env.LOGGER_PII_ENABLED;
|
|
132
|
+
process.env.LOGGER_PII_INCLUDE_DEFAULTS;
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### 5.5 Helpers and key features
|
|
136
|
+
|
|
137
|
+
#### `IFilesystemDatasourceOptions`
|
|
138
|
+
|
|
139
|
+
Public datasource configuration:
|
|
140
|
+
|
|
141
|
+
```ts id="p2z8rk"
|
|
142
|
+
export interface IFilesystemDatasourceOptions {
|
|
143
|
+
basePath: string;
|
|
144
|
+
mkdir?: boolean;
|
|
145
|
+
fileNamePattern?: string;
|
|
146
|
+
rotation?: IFileSystemRotationConfig;
|
|
147
|
+
onRotate?: (oldPath: FilePath, newPath: FilePath) => void | Promise<void>;
|
|
148
|
+
onError?: (error: Error) => void | Promise<void>;
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
#### Rotation
|
|
153
|
+
|
|
154
|
+
The plugin supports the following policies:
|
|
155
|
+
|
|
156
|
+
- `none`
|
|
157
|
+
- `day`
|
|
158
|
+
- `size`
|
|
159
|
+
|
|
160
|
+
Example:
|
|
161
|
+
|
|
162
|
+
```ts id="k9m1hd"
|
|
163
|
+
rotation: { by: "day" }
|
|
164
|
+
rotation: { by: "size", maxSizeMB: 50, maxFiles: 10 }
|
|
165
|
+
rotation: { by: "none" }
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### File name pattern
|
|
169
|
+
|
|
170
|
+
The plugin uses `FileNamePattern` and supports date tokens such as:
|
|
171
|
+
|
|
172
|
+
- `{yyyy}`
|
|
173
|
+
- `{MM}`
|
|
174
|
+
- `{dd}`
|
|
175
|
+
|
|
176
|
+
Example:
|
|
177
|
+
|
|
178
|
+
```ts id="n4t6zx"
|
|
179
|
+
fileNamePattern: "app-{yyyy}{MM}{dd}.log";
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
#### Useful hooks
|
|
183
|
+
|
|
184
|
+
- `onRotate`: notification after rotation
|
|
185
|
+
- `onError`: centralizes datasource errors
|
|
186
|
+
|
|
187
|
+
#### Historical reading
|
|
188
|
+
|
|
189
|
+
The datasource also exposes log search via `find(...)`, supported by:
|
|
190
|
+
|
|
191
|
+
- `.log` file enumeration,
|
|
192
|
+
- line-by-line reading,
|
|
193
|
+
- filtering by level, dates, and text query.
|
|
194
|
+
|
|
195
|
+
### 5.7 Current scenario
|
|
196
|
+
|
|
197
|
+
The documented integration is oriented toward Express and an infrastructure bootstrap similar to what you already use with `@jmlq/logger`, but the plugin remains decoupled from any HTTP framework.
|
|
198
|
+
|
|
199
|
+
## ✅ Checklist (quick steps)
|
|
200
|
+
|
|
201
|
+
- [Install](#51-installation)
|
|
202
|
+
- [Create datasource with `createFsDatasource`](./docs/en/configuration.md#create-the-datasource-with-createfsdatasource)
|
|
203
|
+
- [Configure rotation and file name pattern](./docs/en/configuration.md#datasource-configuration)
|
|
204
|
+
- [Integrate datasource into logger bootstrap](./docs/en/integration-express.md#logger-bootstrap-in-the-host)
|
|
205
|
+
- [Attach logger to Express](./docs/en/integration-express.md#attach-logger-to-request)
|
|
206
|
+
- [Review common issues](./docs/en/troubleshooting.md)
|
|
207
|
+
|
|
208
|
+
## 📌 Menu
|
|
209
|
+
|
|
210
|
+
- [Architecture](./docs/en/architecture.md)
|
|
211
|
+
- [Configuration](./docs/en/configuration.md)
|
|
212
|
+
- [Express Integration](./docs/en/integration-express.md)
|
|
213
|
+
- [Troubleshooting](./docs/en/troubleshooting.md)
|
|
214
|
+
|
|
215
|
+
## 🔗 References
|
|
216
|
+
|
|
217
|
+
- [`@jmlq/logger`](https://github.com/MLahuasi/jmlq-logger#readme)
|
|
218
|
+
- Related ecosystem plugins:
|
|
219
|
+
- [`@jmlq/logger-plugin-mongo`](https://github.com/MLahuasi/jmlq-logger-plugin-mongo#readme)
|
|
220
|
+
- [`@jmlq/logger-plugin-postgresql`](https://github.com/MLahuasi/jmlq-logger-plugin-postgresql#readme)
|
|
221
|
+
|
|
222
|
+
## ⬅️ 🌐 Ecosystem
|
|
223
|
+
|
|
224
|
+
- [`@jmlq`](https://github.com/MLahuasi/jmlq-ecosystem#readme)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./rotate-if-needed.request";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./rotate-if-needed.request"), exports);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FileRotationPolicy } from "../../domain/value-objects";
|
|
2
|
+
/**
|
|
3
|
+
* DTO de entrada para el caso de uso RotateIfNeeded.
|
|
4
|
+
* - currentDate: fecha/hora actual (inyectada desde un clock para tests deterministas)
|
|
5
|
+
* - rotationPolicy: política de rotación (VO de dominio)
|
|
6
|
+
*/
|
|
7
|
+
export interface RotateIfNeededRequest {
|
|
8
|
+
currentDate: Date;
|
|
9
|
+
rotationPolicy: FileRotationPolicy;
|
|
10
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ILogDatasource } from "../../domain/ports";
|
|
2
|
+
import { IFilesystemDatasourceOptions } from "../types";
|
|
3
|
+
/**
|
|
4
|
+
* createFsDatasource
|
|
5
|
+
* -----------------------------------------------------------------------------
|
|
6
|
+
* Composition Root del plugin FS.
|
|
7
|
+
*
|
|
8
|
+
* Responsabilidad:
|
|
9
|
+
* - Construir el grafo de dependencias (VOs, adapters, use-cases)
|
|
10
|
+
* - Exponer un ILogDatasource compatible con @jmlq/logger
|
|
11
|
+
*
|
|
12
|
+
* Clean Architecture:
|
|
13
|
+
* - Vive en infraestructura porque integra con el core externo (@jmlq/logger)
|
|
14
|
+
* - Application/domain permanecen sin dependencias externas.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createFsDatasource(options: IFilesystemDatasourceOptions): ILogDatasource;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// import type { ILogDatasource } from "@jmlq/logger";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.createFsDatasource = createFsDatasource;
|
|
5
|
+
const adapters_1 = require("../../infrastructure/adapters");
|
|
6
|
+
const use_cases_1 = require("../../application/use-cases");
|
|
7
|
+
const value_objects_1 = require("../../domain/value-objects");
|
|
8
|
+
/**
|
|
9
|
+
* createFsDatasource
|
|
10
|
+
* -----------------------------------------------------------------------------
|
|
11
|
+
* Composition Root del plugin FS.
|
|
12
|
+
*
|
|
13
|
+
* Responsabilidad:
|
|
14
|
+
* - Construir el grafo de dependencias (VOs, adapters, use-cases)
|
|
15
|
+
* - Exponer un ILogDatasource compatible con @jmlq/logger
|
|
16
|
+
*
|
|
17
|
+
* Clean Architecture:
|
|
18
|
+
* - Vive en infraestructura porque integra con el core externo (@jmlq/logger)
|
|
19
|
+
* - Application/domain permanecen sin dependencias externas.
|
|
20
|
+
*/
|
|
21
|
+
function createFsDatasource(options) {
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// 1) Value Objects (dominio)
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
const fileNamePattern = new value_objects_1.FileNamePattern(options.fileNamePattern || "app-{yyyy}{MM}{dd}.log");
|
|
26
|
+
const rotationPolicy = new value_objects_1.FileRotationPolicy(options.rotation?.by || "day", options.rotation?.maxSizeMB, options.rotation?.maxFiles);
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// 2) Adapters (infraestructura)
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
const clock = new adapters_1.SystemClockAdapter();
|
|
31
|
+
const filePath = new adapters_1.SystemFilePathAdapter();
|
|
32
|
+
const fsProvider = new adapters_1.FileSystemProviderAdapter();
|
|
33
|
+
const writer = new adapters_1.LogStreamWriterAdapter();
|
|
34
|
+
const fileRotator = new adapters_1.FileRotatorAdapter(fsProvider, filePath, fileNamePattern, options.basePath);
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// 3) Use-cases (application)
|
|
37
|
+
// Nota: no se "exponen" fuera; PersistLog orquesta todo.
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
const ensureDirectoryUseCase = new use_cases_1.EnsureDirectoryUseCase(fsProvider, options.basePath, options.mkdir);
|
|
40
|
+
const appendLogUseCase = new use_cases_1.AppendLogUseCase(writer);
|
|
41
|
+
const rotateIfNeededUseCase = new use_cases_1.RotateIfNeededUseCase(fileRotator, writer, options.onRotate);
|
|
42
|
+
const persistLogUseCase = new use_cases_1.PersistLogUseCase(clock, fileRotator, writer, rotationPolicy, rotateIfNeededUseCase, appendLogUseCase, ensureDirectoryUseCase, options.onError);
|
|
43
|
+
// 3.x) FindLogs use-case + IO
|
|
44
|
+
const fileEnumerator = new adapters_1.FileSystemLogFileEnumeratorAdapter(options.basePath);
|
|
45
|
+
const lineReader = new adapters_1.FileSystemLogFileLineReaderAdapter();
|
|
46
|
+
const findLogsUseCase = new use_cases_1.FindLogsUseCase({ fileEnumerator, lineReader });
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// 4) Adapter que expone el contrato del core (@jmlq/logger)
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
return new adapters_1.FsDatasourceAdapter(persistLogUseCase, writer, findLogsUseCase);
|
|
51
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./create-fs-datasource.factory";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./create-fs-datasource.factory"), exports);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { FilePath } from "../../domain/value-objects";
|
|
2
|
+
import { IFileSystemRotationConfig } from "../../infrastructure/filesystem/types";
|
|
3
|
+
/**
|
|
4
|
+
* Opciones de configuración para la fuente de datos del sistema de archivos.
|
|
5
|
+
* Es el objeto de configuración para un datasource de logs basado en filesystem
|
|
6
|
+
*/
|
|
7
|
+
export interface IFilesystemDatasourceOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Directorio base donde se van a crear/leer los archivos de log.
|
|
10
|
+
*/
|
|
11
|
+
basePath: string;
|
|
12
|
+
/**
|
|
13
|
+
* Indica si se deben crear los directorios padres si no existen
|
|
14
|
+
* Si es true, la implementación puede crear el basePath (con fs.mkdir({ recursive: true })) si no existe.
|
|
15
|
+
* Si es false o undefined, o no lo crea o depende de tu implementación.
|
|
16
|
+
*/
|
|
17
|
+
mkdir?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Patrón de nombre del archivo de log
|
|
20
|
+
*/
|
|
21
|
+
fileNamePattern?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Conecta con la política de rotación: "none" | "day" | "size", tamaño máximo, número de archivos, etc
|
|
24
|
+
*/
|
|
25
|
+
rotation?: IFileSystemRotationConfig;
|
|
26
|
+
/**
|
|
27
|
+
* Hook que se dispara cuando se rota un archivo de log. Útil para:
|
|
28
|
+
* - Notificar a otro sistema.
|
|
29
|
+
* - Enviar el archivo rotado a S3.
|
|
30
|
+
* - Hacer limpieza adicional.
|
|
31
|
+
* @param oldPath Ruta del archivo de log antes de la rotación
|
|
32
|
+
* @param newPath Ruta del archivo de log después de la rotación
|
|
33
|
+
* @returns
|
|
34
|
+
*/
|
|
35
|
+
onRotate?: (oldPath: FilePath, newPath: FilePath) => void | Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Hook centralizado para manejar errores del datasource:
|
|
38
|
+
* - Loggear en otro canal.
|
|
39
|
+
* - Enviar métricas / alertas.
|
|
40
|
+
* - Evitar que el logger “reviente” la app.
|
|
41
|
+
* @param error Error ocurrido en el datasource
|
|
42
|
+
* @returns
|
|
43
|
+
*/
|
|
44
|
+
onError?: (error: Error) => void | Promise<void>;
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./filesystem-datasource-options.type";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./filesystem-datasource-options.type"), exports);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { SaveLogRequest } from "../../domain/request";
|
|
2
|
+
import { ILogStreamWriterPort } from "../../domain/ports";
|
|
3
|
+
/**
|
|
4
|
+
* Contrato del caso de uso: permite ejecutar la operación "append log".
|
|
5
|
+
* Útil si quieres mockearlo en tests o exponerlo vía facade.
|
|
6
|
+
*/
|
|
7
|
+
export interface IAppendLogUseCase {
|
|
8
|
+
execute(dto: SaveLogRequest): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* AppendLogUseCase
|
|
12
|
+
* -----------------------------------------------------------------------------
|
|
13
|
+
* Caso de uso de Application que:
|
|
14
|
+
* - toma un log (request model),
|
|
15
|
+
* - lo serializa (serializer opcional o JSON por defecto),
|
|
16
|
+
* - asegura salto de línea,
|
|
17
|
+
* - lo escribe a través de un port (writer por stream).
|
|
18
|
+
*
|
|
19
|
+
* Clean Architecture:
|
|
20
|
+
* - depende de puertos del dominio (ILogStreamWriterPort)
|
|
21
|
+
* - NO depende de infraestructura directamente.
|
|
22
|
+
*/
|
|
23
|
+
export declare class AppendLogUseCase implements IAppendLogUseCase {
|
|
24
|
+
private readonly logStreamWriter;
|
|
25
|
+
constructor(logStreamWriter: ILogStreamWriterPort);
|
|
26
|
+
/**
|
|
27
|
+
* Ejecuta el caso de uso "append log".
|
|
28
|
+
*/
|
|
29
|
+
execute(dto: SaveLogRequest): Promise<void>;
|
|
30
|
+
}
|