@jmlq/logger-plugin-fs 0.1.0-alpha.8 → 0.1.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/application/dto/index.d.ts +1 -3
- package/dist/application/dto/index.js +1 -3
- package/dist/application/dto/rotate-if-needed.request.d.ts +10 -0
- package/dist/application/factory/create-fs-datasource.factory.d.ts +14 -1
- package/dist/application/factory/create-fs-datasource.factory.js +45 -20
- package/dist/application/use-cases/append-log.use-case.d.ts +26 -8
- package/dist/application/use-cases/append-log.use-case.js +25 -12
- package/dist/application/use-cases/ensure-directory.use-case.d.ts +50 -3
- package/dist/application/use-cases/ensure-directory.use-case.js +44 -7
- 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 +1 -0
- package/dist/application/use-cases/index.js +1 -0
- package/dist/application/use-cases/persist-log.use-case.d.ts +86 -9
- package/dist/application/use-cases/persist-log.use-case.js +73 -15
- package/dist/application/use-cases/rotate-if-needed.use-case.d.ts +49 -11
- package/dist/application/use-cases/rotate-if-needed.use-case.js +41 -8
- package/dist/domain/model/index.d.ts +1 -0
- package/dist/{infrastructure/filesystem/value-objects → domain/model}/index.js +1 -1
- package/dist/domain/model/log-entry.model.d.ts +8 -0
- package/dist/domain/ports/file/file-path.port.d.ts +38 -0
- package/dist/domain/ports/file/file-rotator.port.d.ts +42 -0
- package/dist/{infrastructure/filesystem/ports → domain/ports/file}/index.d.ts +1 -0
- package/dist/{infrastructure/filesystem/ports → domain/ports/file}/index.js +1 -0
- package/dist/domain/ports/file/log-stream-writer.port.d.ts +70 -0
- package/dist/domain/ports/{fs-provider.port.d.ts → filesystem-provider.port.d.ts} +1 -1
- package/dist/domain/ports/index.d.ts +5 -4
- package/dist/domain/ports/index.js +5 -4
- 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-numerator.port.d.ts +3 -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/{clock.port.d.ts → system-clock.port.d.ts} +1 -1
- 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/{application/services → domain/response}/index.js +1 -1
- 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 +73 -9
- package/dist/domain/value-objects/file-path.vo.js +54 -13
- 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 +61 -0
- package/dist/domain/value-objects/file-size.vo.js +57 -0
- package/dist/domain/value-objects/index.d.ts +3 -0
- package/dist/domain/value-objects/index.js +3 -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 -4
- package/dist/index.js +5 -11
- package/dist/infrastructure/adapters/file-rotator.adapter.d.ts +67 -8
- package/dist/infrastructure/adapters/file-rotator.adapter.js +133 -67
- 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/{fs-provider.adapter.js → filesystem-log-file-line-reader.adapter.js} +13 -37
- 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 +7 -4
- package/dist/infrastructure/adapters/index.js +7 -4
- 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/{shared → infrastructure}/errors/index.js +0 -2
- 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 +0 -3
- package/dist/infrastructure/filesystem/index.js +0 -3
- package/dist/infrastructure/filesystem/types/filesystem-datasource-options.type.d.ts +2 -6
- package/dist/infrastructure/filesystem/types/filesystem-rotation.type.d.ts +2 -9
- package/dist/infrastructure/filesystem/types/index.d.ts +0 -1
- package/dist/infrastructure/filesystem/types/index.js +0 -1
- package/package.json +3 -5
- package/dist/application/dto/rotation-check.dto.d.ts +0 -5
- package/dist/application/dto/save-log.dto.d.ts +0 -4
- package/dist/application/dto/write-operation.dto.d.ts +0 -5
- package/dist/application/services/fs-datasource.service.d.ts +0 -11
- package/dist/application/services/fs-datasource.service.js +0 -19
- package/dist/application/services/index.d.ts +0 -1
- package/dist/domain/ports/file-path-adapter.port.d.ts +0 -33
- package/dist/domain/ports/stream-writer.port.d.ts +0 -42
- package/dist/infrastructure/adapters/fs-provider.adapter.d.ts +0 -17
- package/dist/infrastructure/adapters/fs-writer.adapter.d.ts +0 -13
- package/dist/infrastructure/adapters/fs-writer.adapter.js +0 -71
- package/dist/infrastructure/adapters/node-clock.adapter.d.ts +0 -4
- package/dist/infrastructure/adapters/node-clock.adapter.js +0 -9
- package/dist/infrastructure/adapters/node-file-path.adapter.d.ts +0 -16
- package/dist/infrastructure/adapters/node-file-path.adapter.js +0 -117
- package/dist/infrastructure/filesystem/polices/index.d.ts +0 -1
- package/dist/infrastructure/filesystem/polices/index.js +0 -5
- package/dist/infrastructure/filesystem/polices/rotation-policy.d.ts +0 -29
- package/dist/infrastructure/filesystem/polices/rotation-policy.js +0 -55
- package/dist/infrastructure/filesystem/ports/file-rotator.port.d.ts +0 -32
- package/dist/infrastructure/filesystem/types/filesystem-serializer.type.d.ts +0 -10
- package/dist/infrastructure/filesystem/value-objects/file-name-pattern.vo.d.ts +0 -22
- package/dist/infrastructure/filesystem/value-objects/file-name-pattern.vo.js +0 -37
- package/dist/infrastructure/filesystem/value-objects/index.d.ts +0 -1
- package/dist/shared/errors/file-operation.error.d.ts +0 -12
- package/dist/shared/errors/file-operation.error.js +0 -32
- package/dist/shared/errors/fs-plugin.error.d.ts +0 -4
- package/dist/shared/errors/fs-plugin.error.js +0 -11
- package/dist/shared/errors/index.d.ts +0 -3
- package/dist/shared/errors/rotation.error.d.ts +0 -10
- package/dist/shared/errors/rotation.error.js +0 -25
- /package/dist/application/dto/{rotation-check.dto.js → rotate-if-needed.request.js} +0 -0
- /package/dist/{application/dto/save-log.dto.js → domain/model/log-entry.model.js} +0 -0
- /package/dist/{application/dto/write-operation.dto.js → domain/ports/file/file-path.port.js} +0 -0
- /package/dist/{infrastructure/filesystem/ports → domain/ports/file}/file-rotator.port.js +0 -0
- /package/dist/domain/ports/{clock.port.js → file/log-stream-writer.port.js} +0 -0
- /package/dist/domain/ports/{file-path-adapter.port.js → filesystem-provider.port.js} +0 -0
- /package/dist/domain/ports/{fs-provider.port.js → logs/find/log-file-line-reader.port.js} +0 -0
- /package/dist/domain/ports/{stream-writer.port.js → logs/find/log-file-numerator.port.js} +0 -0
- /package/dist/{infrastructure/filesystem/types/filesystem-serializer.type.js → domain/ports/logs/log-datasource.port.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.createFsDatasource = exports.FileNamePattern = exports.FileRotationPolicy = exports.FileSize = exports.FilePath = void 0;
|
|
4
4
|
// Value Objects
|
|
5
5
|
var value_objects_1 = require("./domain/value-objects");
|
|
6
6
|
Object.defineProperty(exports, "FilePath", { enumerable: true, get: function () { return value_objects_1.FilePath; } });
|
|
7
7
|
Object.defineProperty(exports, "FileSize", { enumerable: true, get: function () { return value_objects_1.FileSize; } });
|
|
8
|
+
Object.defineProperty(exports, "FileRotationPolicy", { enumerable: true, get: function () { return value_objects_1.FileRotationPolicy; } });
|
|
9
|
+
Object.defineProperty(exports, "FileNamePattern", { enumerable: true, get: function () { return value_objects_1.FileNamePattern; } });
|
|
8
10
|
// Factory
|
|
9
|
-
var
|
|
10
|
-
Object.defineProperty(exports, "createFsDatasource", { enumerable: true, get: function () { return
|
|
11
|
-
// Errors
|
|
12
|
-
var errors_1 = require("./shared/errors");
|
|
13
|
-
Object.defineProperty(exports, "FsPluginError", { enumerable: true, get: function () { return errors_1.FsPluginError; } });
|
|
14
|
-
Object.defineProperty(exports, "FileOperationError", { enumerable: true, get: function () { return errors_1.FileOperationError; } });
|
|
15
|
-
Object.defineProperty(exports, "RotationError", { enumerable: true, get: function () { return errors_1.RotationError; } });
|
|
16
|
-
var filesystem_1 = require("./infrastructure/filesystem");
|
|
17
|
-
Object.defineProperty(exports, "FileNamePattern", { enumerable: true, get: function () { return filesystem_1.FileNamePattern; } });
|
|
18
|
-
Object.defineProperty(exports, "RotationPolicy", { enumerable: true, get: function () { return filesystem_1.RotationPolicy; } });
|
|
11
|
+
var create_fs_datasource_factory_1 = require("./application/factory/create-fs-datasource.factory");
|
|
12
|
+
Object.defineProperty(exports, "createFsDatasource", { enumerable: true, get: function () { return create_fs_datasource_factory_1.createFsDatasource; } });
|
|
@@ -1,20 +1,79 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { FileSize, FilePath } from "../../domain/value-objects";
|
|
3
|
-
|
|
1
|
+
import { IFileSystemProviderPort, IFilePathPort, IFileRotatorPort } from "../../domain/ports";
|
|
2
|
+
import { FileSize, FilePath, FileRotationPolicy, FileNamePattern } from "../../domain/value-objects";
|
|
3
|
+
/**
|
|
4
|
+
* Adapter de infraestructura que implementa IFileRotatorPort.
|
|
5
|
+
*
|
|
6
|
+
* Responsabilidad:
|
|
7
|
+
* - Calcular el path esperado del archivo de log en base a una fecha y un FileNamePattern.
|
|
8
|
+
* - Leer metadata real del filesystem (tamaño / listado de archivos).
|
|
9
|
+
* - Decidir si debe rotar (por día o por tamaño) apoyándose en la política del dominio.
|
|
10
|
+
*
|
|
11
|
+
* Nota:
|
|
12
|
+
* - Este adapter mantiene estado mínimo (`currentFilePath`) porque el Port lo requiere.
|
|
13
|
+
* Aun así, evitamos mutaciones ocultas: solo se actualiza desde getExpectedPathForDate().
|
|
14
|
+
*/
|
|
4
15
|
export declare class FileRotatorAdapter implements IFileRotatorPort {
|
|
5
16
|
private readonly fsProvider;
|
|
6
17
|
private readonly filePathAdapter;
|
|
7
18
|
private readonly fileNamePattern;
|
|
8
19
|
private readonly basePath;
|
|
9
20
|
private currentFilePath;
|
|
10
|
-
|
|
21
|
+
private readonly baseDir;
|
|
22
|
+
private static readonly TOKEN_REGEX;
|
|
23
|
+
constructor(fsProvider: IFileSystemProviderPort, filePathAdapter: IFilePathPort, fileNamePattern: FileNamePattern, basePath: string);
|
|
24
|
+
/**
|
|
25
|
+
* Devuelve el último archivo considerado “actual” por el rotator.
|
|
26
|
+
* Puede ser null si aún no se ha calculado/solicitado un path.
|
|
27
|
+
*/
|
|
11
28
|
getCurrentPath(): FilePath | null;
|
|
29
|
+
/**
|
|
30
|
+
* Calcula el path esperado para una fecha y lo “marca” como archivo actual.
|
|
31
|
+
* OJO: este es el único método que muta currentFilePath a propósito.
|
|
32
|
+
*/
|
|
12
33
|
getExpectedPathForDate(date: Date): FilePath;
|
|
13
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Calcula el FilePath esperado para una fecha usando el patrón.
|
|
36
|
+
* Método “puro”: NO muta estado.
|
|
37
|
+
*/
|
|
38
|
+
private computePathForDate;
|
|
39
|
+
/**
|
|
40
|
+
* Reemplaza tokens de fecha dentro del patrón (ej. {yyyy}{MM}{dd}) por valores reales.
|
|
41
|
+
*/
|
|
42
|
+
private applyDateTokens;
|
|
43
|
+
/**
|
|
44
|
+
* Obtiene el tamaño del archivo (stat) y lo devuelve como FileSize (VO).
|
|
45
|
+
*
|
|
46
|
+
* Decisión de diseño:
|
|
47
|
+
* - Si stat falla (archivo no existe, permisos, etc.), devolvemos tamaño 0.
|
|
48
|
+
* - Esto evita que el flujo de rotación “reviente” por un fallo de I/O puntual.
|
|
49
|
+
* - Si quieres hacer esto más estricto, aquí podrías lanzar un FileOperationError("read"/"stat", ...).
|
|
50
|
+
*/
|
|
14
51
|
getFileSize(filePath: FilePath): Promise<FileSize>;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Decide si debe rotar basándose en la política del dominio y el estado actual.
|
|
54
|
+
*
|
|
55
|
+
* Nota:
|
|
56
|
+
* - Para rotación por día: comparamos el path actual vs el esperado para la fecha actual.
|
|
57
|
+
* - Para rotación por tamaño: consultamos el tamaño real y delegamos la regla al VO.
|
|
58
|
+
*/
|
|
59
|
+
shouldRotate(policy: FileRotationPolicy, currentDate: Date): Promise<boolean>;
|
|
60
|
+
/**
|
|
61
|
+
* Rotación por día:
|
|
62
|
+
* - Si no hay currentFilePath, se considera que “debe rotar/crear” para inicializar.
|
|
63
|
+
* - Si el nombre esperado para la fecha actual difiere del actual, debe rotar.
|
|
64
|
+
*
|
|
65
|
+
* Importante:
|
|
66
|
+
* - Este método NO muta currentFilePath (solo calcula).
|
|
67
|
+
*/
|
|
18
68
|
private shouldRotateByDay;
|
|
69
|
+
/**
|
|
70
|
+
* Rotación por tamaño:
|
|
71
|
+
* - Si no hay currentFilePath, no rotamos (no hay “archivo actual” que evaluar).
|
|
72
|
+
* - Si no hay maxSize en la policy, no rotamos.
|
|
73
|
+
* - Si se puede medir tamaño, delegamos al VO para la regla (>= maxSize).
|
|
74
|
+
*/
|
|
19
75
|
private shouldRotateBySize;
|
|
20
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Escapa caracteres especiales para construir RegExp seguro desde strings (basename/ext).
|
|
79
|
+
*/
|
|
@@ -2,38 +2,103 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FileRotatorAdapter = void 0;
|
|
4
4
|
const value_objects_1 = require("../../domain/value-objects");
|
|
5
|
+
/**
|
|
6
|
+
* Adapter de infraestructura que implementa IFileRotatorPort.
|
|
7
|
+
*
|
|
8
|
+
* Responsabilidad:
|
|
9
|
+
* - Calcular el path esperado del archivo de log en base a una fecha y un FileNamePattern.
|
|
10
|
+
* - Leer metadata real del filesystem (tamaño / listado de archivos).
|
|
11
|
+
* - Decidir si debe rotar (por día o por tamaño) apoyándose en la política del dominio.
|
|
12
|
+
*
|
|
13
|
+
* Nota:
|
|
14
|
+
* - Este adapter mantiene estado mínimo (`currentFilePath`) porque el Port lo requiere.
|
|
15
|
+
* Aun así, evitamos mutaciones ocultas: solo se actualiza desde getExpectedPathForDate().
|
|
16
|
+
*/
|
|
5
17
|
class FileRotatorAdapter {
|
|
6
|
-
constructor(
|
|
18
|
+
constructor(
|
|
19
|
+
// Port de FS (stat, readdir, etc.)
|
|
20
|
+
fsProvider,
|
|
21
|
+
// Port de paths (normalización, join, resolve, etc.)
|
|
22
|
+
filePathAdapter,
|
|
23
|
+
// VO de dominio: patrón de nombre
|
|
24
|
+
fileNamePattern,
|
|
25
|
+
// Config cruda (normalmente string proveniente de env/config)
|
|
26
|
+
basePath) {
|
|
7
27
|
this.fsProvider = fsProvider;
|
|
8
28
|
this.filePathAdapter = filePathAdapter;
|
|
9
29
|
this.fileNamePattern = fileNamePattern;
|
|
10
30
|
this.basePath = basePath;
|
|
31
|
+
// Estado mínimo: “archivo actual” según el último cálculo/uso.
|
|
11
32
|
this.currentFilePath = null;
|
|
33
|
+
// Resolver y normalizar basePath una sola vez.
|
|
34
|
+
this.baseDir = this.filePathAdapter.fromRaw(this.basePath);
|
|
12
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Devuelve el último archivo considerado “actual” por el rotator.
|
|
38
|
+
* Puede ser null si aún no se ha calculado/solicitado un path.
|
|
39
|
+
*/
|
|
13
40
|
getCurrentPath() {
|
|
14
41
|
return this.currentFilePath;
|
|
15
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Calcula el path esperado para una fecha y lo “marca” como archivo actual.
|
|
45
|
+
* OJO: este es el único método que muta currentFilePath a propósito.
|
|
46
|
+
*/
|
|
16
47
|
getExpectedPathForDate(date) {
|
|
17
|
-
const
|
|
18
|
-
this.currentFilePath =
|
|
19
|
-
return
|
|
48
|
+
const expected = this.computePathForDate(date);
|
|
49
|
+
this.currentFilePath = expected;
|
|
50
|
+
return expected;
|
|
20
51
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Calcula el FilePath esperado para una fecha usando el patrón.
|
|
54
|
+
* Método “puro”: NO muta estado.
|
|
55
|
+
*/
|
|
56
|
+
computePathForDate(date) {
|
|
57
|
+
// 1) Aplicar reemplazo de tokens al patrón -> obtenemos el nombre del archivo.
|
|
58
|
+
const fileName = this.applyDateTokens(this.fileNamePattern.pattern, date);
|
|
59
|
+
// 2) Unir baseDir + fileName (sin re-resolver basePath en cada llamada).
|
|
60
|
+
return this.filePathAdapter.join(this.baseDir, fileName);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Reemplaza tokens de fecha dentro del patrón (ej. {yyyy}{MM}{dd}) por valores reales.
|
|
64
|
+
*/
|
|
65
|
+
applyDateTokens(pattern, date) {
|
|
66
|
+
// Normalizamos valores una sola vez.
|
|
67
|
+
const yyyy = date.getFullYear().toString();
|
|
68
|
+
const MM = String(date.getMonth() + 1).padStart(2, "0");
|
|
69
|
+
const dd = String(date.getDate()).padStart(2, "0");
|
|
70
|
+
const HH = String(date.getHours()).padStart(2, "0");
|
|
71
|
+
const mm = String(date.getMinutes()).padStart(2, "0");
|
|
72
|
+
const ss = String(date.getSeconds()).padStart(2, "0");
|
|
73
|
+
// Reemplazamos usando regex global; más simple y eficiente que loop + new RegExp por token.
|
|
74
|
+
return pattern.replace(FileRotatorAdapter.TOKEN_REGEX, (_m, token) => {
|
|
75
|
+
switch (token) {
|
|
76
|
+
case "yyyy":
|
|
77
|
+
return yyyy;
|
|
78
|
+
case "MM":
|
|
79
|
+
return MM;
|
|
80
|
+
case "dd":
|
|
81
|
+
return dd;
|
|
82
|
+
case "HH":
|
|
83
|
+
return HH;
|
|
84
|
+
case "mm":
|
|
85
|
+
return mm;
|
|
86
|
+
case "ss":
|
|
87
|
+
return ss;
|
|
88
|
+
default:
|
|
89
|
+
// Defensive: no debería ocurrir por la regex.
|
|
90
|
+
return _m;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
36
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Obtiene el tamaño del archivo (stat) y lo devuelve como FileSize (VO).
|
|
96
|
+
*
|
|
97
|
+
* Decisión de diseño:
|
|
98
|
+
* - Si stat falla (archivo no existe, permisos, etc.), devolvemos tamaño 0.
|
|
99
|
+
* - Esto evita que el flujo de rotación “reviente” por un fallo de I/O puntual.
|
|
100
|
+
* - Si quieres hacer esto más estricto, aquí podrías lanzar un FileOperationError("read"/"stat", ...).
|
|
101
|
+
*/
|
|
37
102
|
async getFileSize(filePath) {
|
|
38
103
|
try {
|
|
39
104
|
const stats = await this.fsProvider.stat(filePath.absolutePath);
|
|
@@ -43,63 +108,64 @@ class FileRotatorAdapter {
|
|
|
43
108
|
return new value_objects_1.FileSize(0);
|
|
44
109
|
}
|
|
45
110
|
}
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
let maxIndex = 0;
|
|
57
|
-
for (const file of files) {
|
|
58
|
-
const match = file.match(pattern);
|
|
59
|
-
if (match) {
|
|
60
|
-
const index = parseInt(match[1], 10);
|
|
61
|
-
if (index > maxIndex) {
|
|
62
|
-
maxIndex = index;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return maxIndex + 1;
|
|
67
|
-
}
|
|
68
|
-
catch {
|
|
69
|
-
return 1;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
// Decisión de rotación
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
/**
|
|
115
|
+
* Decide si debe rotar basándose en la política del dominio y el estado actual.
|
|
116
|
+
*
|
|
117
|
+
* Nota:
|
|
118
|
+
* - Para rotación por día: comparamos el path actual vs el esperado para la fecha actual.
|
|
119
|
+
* - Para rotación por tamaño: consultamos el tamaño real y delegamos la regla al VO.
|
|
120
|
+
*/
|
|
72
121
|
async shouldRotate(policy, currentDate) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
122
|
+
switch (policy.by) {
|
|
123
|
+
case "none":
|
|
124
|
+
return false;
|
|
125
|
+
case "day":
|
|
126
|
+
return this.shouldRotateByDay(currentDate);
|
|
127
|
+
case "size":
|
|
128
|
+
return this.shouldRotateBySize(policy);
|
|
129
|
+
default:
|
|
130
|
+
// Defensive: si el tipo llegara corrupto por casting/JS.
|
|
131
|
+
return false;
|
|
81
132
|
}
|
|
82
|
-
return false;
|
|
83
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Rotación por día:
|
|
136
|
+
* - Si no hay currentFilePath, se considera que “debe rotar/crear” para inicializar.
|
|
137
|
+
* - Si el nombre esperado para la fecha actual difiere del actual, debe rotar.
|
|
138
|
+
*
|
|
139
|
+
* Importante:
|
|
140
|
+
* - Este método NO muta currentFilePath (solo calcula).
|
|
141
|
+
*/
|
|
84
142
|
shouldRotateByDay(currentDate) {
|
|
85
|
-
if (!this.currentFilePath)
|
|
86
|
-
return true;
|
|
87
|
-
|
|
88
|
-
// Ahora solo calculamos, NO mutamos currentFilePath
|
|
89
|
-
const expectedPath = this.buildPathForDate(currentDate);
|
|
143
|
+
if (!this.currentFilePath)
|
|
144
|
+
return true;
|
|
145
|
+
const expectedPath = this.computePathForDate(currentDate);
|
|
90
146
|
return !this.currentFilePath.equals(expectedPath);
|
|
91
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Rotación por tamaño:
|
|
150
|
+
* - Si no hay currentFilePath, no rotamos (no hay “archivo actual” que evaluar).
|
|
151
|
+
* - Si no hay maxSize en la policy, no rotamos.
|
|
152
|
+
* - Si se puede medir tamaño, delegamos al VO para la regla (>= maxSize).
|
|
153
|
+
*/
|
|
92
154
|
async shouldRotateBySize(policy) {
|
|
93
|
-
if (!this.currentFilePath
|
|
155
|
+
if (!this.currentFilePath)
|
|
94
156
|
return false;
|
|
95
|
-
|
|
96
|
-
try {
|
|
97
|
-
const currentFileSize = await this.getFileSize(this.currentFilePath);
|
|
98
|
-
return policy.shouldRotateBySize(currentFileSize);
|
|
99
|
-
}
|
|
100
|
-
catch {
|
|
157
|
+
if (!policy.maxSize)
|
|
101
158
|
return false;
|
|
102
|
-
|
|
159
|
+
const currentFileSize = await this.getFileSize(this.currentFilePath);
|
|
160
|
+
return policy.shouldRotateBySize(currentFileSize);
|
|
103
161
|
}
|
|
104
162
|
}
|
|
105
163
|
exports.FileRotatorAdapter = FileRotatorAdapter;
|
|
164
|
+
// Regex precalculada para encontrar tokens del tipo {yyyy}, {MM}, etc.
|
|
165
|
+
FileRotatorAdapter.TOKEN_REGEX = /\{(yyyy|MM|dd|HH|mm|ss)\}/g;
|
|
166
|
+
/**
|
|
167
|
+
* Escapa caracteres especiales para construir RegExp seguro desde strings (basename/ext).
|
|
168
|
+
*/
|
|
169
|
+
// function escapeRegExp(input: string): string {
|
|
170
|
+
// return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
171
|
+
// }
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ILogDatasource, LogEntry as CoreLogEntry, LogSearchRequest, LogRecord } from "@jmlq/logger";
|
|
2
|
+
import type { FindLogsUseCase, IPersistLogUseCase } from "../../application/use-cases";
|
|
3
|
+
import type { ILogStreamWriterPort } from "../../domain/ports";
|
|
4
|
+
export declare class FsDatasourceAdapter implements ILogDatasource {
|
|
5
|
+
private readonly persistLogUseCase;
|
|
6
|
+
private readonly streamWriterPort;
|
|
7
|
+
private readonly findLogsUseCase?;
|
|
8
|
+
readonly name = "fs";
|
|
9
|
+
constructor(persistLogUseCase: IPersistLogUseCase, streamWriterPort: ILogStreamWriterPort, findLogsUseCase?: FindLogsUseCase | undefined);
|
|
10
|
+
/**
|
|
11
|
+
* Firma EXACTA requerida por @jmlq/logger:
|
|
12
|
+
* save(log: LogEntry): Promise<void>
|
|
13
|
+
*/
|
|
14
|
+
save(log: CoreLogEntry): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Firma típica de @jmlq/logger (si existe en tu interface):
|
|
17
|
+
* find?(filter?: LogFilterRequest): Promise<ILogResponse[]>
|
|
18
|
+
*
|
|
19
|
+
* Por ahora, dejamos una implementación mínima coherente:
|
|
20
|
+
* - Si aún no soportas lectura, devuelve [] (o lanza un error explícito).
|
|
21
|
+
* - Te recomiendo implementar find en serio (tail/list+parse) como acordamos.
|
|
22
|
+
*/
|
|
23
|
+
find?(filter?: LogSearchRequest): Promise<LogRecord[]>;
|
|
24
|
+
flush(): Promise<void>;
|
|
25
|
+
dispose(): Promise<void>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FsDatasourceAdapter = void 0;
|
|
4
|
+
class FsDatasourceAdapter {
|
|
5
|
+
constructor(persistLogUseCase, streamWriterPort, findLogsUseCase) {
|
|
6
|
+
this.persistLogUseCase = persistLogUseCase;
|
|
7
|
+
this.streamWriterPort = streamWriterPort;
|
|
8
|
+
this.findLogsUseCase = findLogsUseCase;
|
|
9
|
+
this.name = "fs";
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Firma EXACTA requerida por @jmlq/logger:
|
|
13
|
+
* save(log: LogEntry): Promise<void>
|
|
14
|
+
*/
|
|
15
|
+
async save(log) {
|
|
16
|
+
const dto = {
|
|
17
|
+
log,
|
|
18
|
+
};
|
|
19
|
+
await this.persistLogUseCase.execute(dto);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Firma típica de @jmlq/logger (si existe en tu interface):
|
|
23
|
+
* find?(filter?: LogFilterRequest): Promise<ILogResponse[]>
|
|
24
|
+
*
|
|
25
|
+
* Por ahora, dejamos una implementación mínima coherente:
|
|
26
|
+
* - Si aún no soportas lectura, devuelve [] (o lanza un error explícito).
|
|
27
|
+
* - Te recomiendo implementar find en serio (tail/list+parse) como acordamos.
|
|
28
|
+
*/
|
|
29
|
+
async find(filter) {
|
|
30
|
+
if (!this.findLogsUseCase)
|
|
31
|
+
return [];
|
|
32
|
+
// mapeo 1:1 (misma estructura)
|
|
33
|
+
const internalFilter = filter;
|
|
34
|
+
const internal = (await this.findLogsUseCase.execute(internalFilter));
|
|
35
|
+
// mapeo 1:1
|
|
36
|
+
return internal;
|
|
37
|
+
}
|
|
38
|
+
async flush() {
|
|
39
|
+
await this.streamWriterPort.flush();
|
|
40
|
+
}
|
|
41
|
+
async dispose() {
|
|
42
|
+
await this.streamWriterPort.close();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.FsDatasourceAdapter = FsDatasourceAdapter;
|
|
@@ -0,0 +1,54 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.FileSystemLogFileEnumeratorAdapter = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
class FileSystemLogFileEnumeratorAdapter {
|
|
40
|
+
constructor(basePath) {
|
|
41
|
+
this.basePath = basePath;
|
|
42
|
+
}
|
|
43
|
+
async listLogFiles() {
|
|
44
|
+
const entries = await fs.promises.readdir(this.basePath, {
|
|
45
|
+
withFileTypes: true,
|
|
46
|
+
});
|
|
47
|
+
return (entries
|
|
48
|
+
.filter((e) => e.isFile() && e.name.endsWith(".log"))
|
|
49
|
+
.map((e) => path.join(this.basePath, e.name))
|
|
50
|
+
// opcional: ordenar por nombre para estabilidad
|
|
51
|
+
.sort());
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.FileSystemLogFileEnumeratorAdapter = FileSystemLogFileEnumeratorAdapter;
|
|
@@ -33,45 +33,21 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.
|
|
37
|
-
const fs = __importStar(require("fs
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
exports.FileSystemLogFileLineReaderAdapter = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const readline = __importStar(require("readline"));
|
|
39
|
+
class FileSystemLogFileLineReaderAdapter {
|
|
40
|
+
async *readLines(filePath) {
|
|
41
|
+
const stream = fs.createReadStream(filePath, { encoding: "utf8" });
|
|
42
|
+
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
40
43
|
try {
|
|
41
|
-
await
|
|
42
|
-
|
|
44
|
+
for await (const line of rl)
|
|
45
|
+
yield line;
|
|
43
46
|
}
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
finally {
|
|
48
|
+
rl.close();
|
|
49
|
+
stream.close();
|
|
46
50
|
}
|
|
47
51
|
}
|
|
48
|
-
async mkdir(path, options) {
|
|
49
|
-
await fs.mkdir(path, options);
|
|
50
|
-
}
|
|
51
|
-
async readFile(path) {
|
|
52
|
-
return fs.readFile(path);
|
|
53
|
-
}
|
|
54
|
-
async writeFile(path, data) {
|
|
55
|
-
await fs.writeFile(path, data);
|
|
56
|
-
}
|
|
57
|
-
async appendFile(path, data) {
|
|
58
|
-
await fs.appendFile(path, data);
|
|
59
|
-
}
|
|
60
|
-
async stat(path) {
|
|
61
|
-
const stats = await fs.stat(path);
|
|
62
|
-
return {
|
|
63
|
-
size: stats.size,
|
|
64
|
-
mtime: stats.mtime,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
async readdir(path) {
|
|
68
|
-
return fs.readdir(path);
|
|
69
|
-
}
|
|
70
|
-
async unlink(path) {
|
|
71
|
-
await fs.unlink(path);
|
|
72
|
-
}
|
|
73
|
-
async rename(oldPath, newPath) {
|
|
74
|
-
await fs.rename(oldPath, newPath);
|
|
75
|
-
}
|
|
76
52
|
}
|
|
77
|
-
exports.
|
|
53
|
+
exports.FileSystemLogFileLineReaderAdapter = FileSystemLogFileLineReaderAdapter;
|