@jmlq/logger 0.1.0-alpha.1 → 0.1.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +307 -0
- package/architecture.md +171 -0
- package/dist/examples/data-source-service.example.d.ts +3 -0
- package/dist/examples/data-source-service.example.js +174 -0
- package/dist/examples/flush-buffers-use-case.example.d.ts +3 -0
- package/dist/examples/flush-buffers-use-case.example.js +60 -0
- package/dist/examples/get-logs-use-case.example.d.ts +3 -0
- package/dist/examples/get-logs-use-case.example.js +110 -0
- package/dist/examples/index.example.d.ts +8 -0
- package/dist/examples/index.example.js +116 -0
- package/dist/examples/logger-factory.example.d.ts +39 -0
- package/dist/examples/logger-factory.example.js +158 -0
- package/dist/examples/normalize-message.example.d.ts +3 -0
- package/dist/examples/normalize-message.example.js +80 -0
- package/dist/examples/pii-redactor.example.d.ts +3 -0
- package/dist/examples/pii-redactor.example.js +129 -0
- package/dist/examples/save-log-use-case.example.d.ts +3 -0
- package/dist/examples/save-log-use-case.example.js +150 -0
- package/dist/examples/to-log-level.example.d.ts +3 -0
- package/dist/examples/to-log-level.example.js +49 -0
- package/dist/examples/to-pii-regex.example.d.ts +3 -0
- package/dist/examples/to-pii-regex.example.js +75 -0
- package/dist/{presentation/factory/index.d.ts → src/application/factory/create-logger.d.ts} +1 -1
- package/dist/src/application/factory/create-logger.js +29 -0
- package/dist/src/application/factory/index.d.ts +1 -0
- package/dist/{config → src/application/factory}/index.js +1 -2
- package/dist/src/application/factory/logger.factory.d.ts +12 -0
- package/dist/src/application/factory/logger.factory.js +74 -0
- package/dist/src/application/index.d.ts +2 -0
- package/dist/{presentation → src/application}/index.js +1 -0
- package/dist/src/application/use-cases/flush-buffers.use-case.d.ts +6 -0
- package/dist/src/application/use-cases/flush-buffers.use-case.js +13 -0
- package/dist/src/application/use-cases/get-logs.use-case.d.ts +8 -0
- package/dist/src/application/use-cases/get-logs.use-case.js +24 -0
- package/dist/src/application/use-cases/index.d.ts +3 -0
- package/dist/src/application/use-cases/index.js +19 -0
- package/dist/src/application/use-cases/save-log.use-case.d.ts +8 -0
- package/dist/src/application/use-cases/save-log.use-case.js +26 -0
- package/dist/src/domain/index.d.ts +6 -0
- package/dist/src/domain/index.js +22 -0
- package/dist/src/domain/ports/create-logger-options.port.d.ts +7 -0
- package/dist/{config/interfaces/index.js → src/domain/ports/create-logger-options.port.js} +0 -1
- package/dist/src/domain/ports/index.d.ts +6 -0
- package/dist/src/domain/ports/index.js +22 -0
- package/dist/src/domain/ports/log-datasource.port.d.ts +9 -0
- package/dist/src/domain/ports/log-datasource.port.js +2 -0
- package/dist/src/domain/ports/logger-factory-config.port.d.ts +28 -0
- package/dist/src/domain/ports/logger-factory-config.port.js +2 -0
- package/dist/src/domain/ports/logger-service.port.d.ts +19 -0
- package/dist/src/domain/ports/logger-service.port.js +2 -0
- package/dist/src/domain/ports/logger.port.d.ts +10 -0
- package/dist/src/domain/ports/logger.port.js +2 -0
- package/dist/src/domain/ports/pii-redactor.port.d.ts +5 -0
- package/dist/src/domain/ports/pii-redactor.port.js +2 -0
- package/dist/src/domain/request/get-logs-filter.props.d.ts +9 -0
- package/dist/src/domain/request/get-logs-filter.props.js +2 -0
- package/dist/src/domain/request/index.d.ts +5 -0
- package/dist/src/domain/request/index.js +21 -0
- package/dist/src/domain/request/log.props.d.ts +7 -0
- package/dist/src/domain/request/log.props.js +2 -0
- package/dist/src/domain/request/pii-options.props.d.ts +8 -0
- package/dist/src/domain/request/pii-options.props.js +2 -0
- package/dist/src/domain/request/pii-replacement.props.d.ts +5 -0
- package/dist/src/domain/request/pii-replacement.props.js +2 -0
- package/dist/src/domain/request/save-log.props.d.ts +7 -0
- package/dist/src/domain/request/save-log.props.js +2 -0
- package/dist/src/domain/response/index.d.ts +1 -0
- package/dist/{domain/services → src/domain/response}/index.js +1 -1
- package/dist/src/domain/response/log.response.d.ts +7 -0
- package/dist/src/domain/response/log.response.js +2 -0
- package/dist/src/domain/services/index.d.ts +4 -0
- package/dist/{index.js → src/domain/services/index.js} +4 -4
- package/dist/src/domain/services/log-level.service.d.ts +2 -0
- package/dist/src/domain/services/log-level.service.js +27 -0
- package/dist/src/domain/services/message-normalizer.service.d.ts +3 -0
- package/dist/src/domain/services/message-normalizer.service.js +8 -0
- package/dist/src/domain/services/pii-pattern.service.d.ts +2 -0
- package/dist/src/domain/services/pii-pattern.service.js +13 -0
- package/dist/src/domain/services/pii-redactor.d.ts +10 -0
- package/dist/src/domain/services/pii-redactor.js +68 -0
- package/dist/src/domain/services/pii-redactor.service.d.ts +10 -0
- package/dist/src/domain/services/pii-redactor.service.js +68 -0
- package/dist/src/domain/types/index.d.ts +1 -0
- package/dist/src/domain/types/index.js +17 -0
- package/dist/src/domain/types/log-message.type.d.ts +1 -0
- package/dist/src/domain/types/log-message.type.js +2 -0
- package/dist/src/domain/value-objects/index.d.ts +1 -0
- package/dist/src/domain/value-objects/index.js +17 -0
- package/dist/src/domain/value-objects/log-level.vo.d.ts +8 -0
- package/dist/src/domain/value-objects/log-level.vo.js +13 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.js +22 -0
- package/dist/src/infrastructure/datasources/in-memory-log.datasource.d.ts +1 -0
- package/dist/src/infrastructure/datasources/in-memory-log.datasource.js +2 -0
- package/dist/src/infrastructure/datasources/index.d.ts +1 -0
- package/dist/src/infrastructure/datasources/index.js +17 -0
- package/dist/src/infrastructure/services/data-source-error-handler.type.d.ts +5 -0
- package/dist/src/infrastructure/services/data-source-error-handler.type.js +2 -0
- package/dist/src/infrastructure/services/datasource.service.d.ts +15 -0
- package/dist/src/infrastructure/services/datasource.service.js +63 -0
- package/dist/src/infrastructure/services/index.d.ts +2 -0
- package/dist/src/infrastructure/services/index.js +18 -0
- package/dist/tests/application/factory/logger-factory.spec.d.ts +1 -0
- package/dist/tests/application/factory/logger-factory.spec.js +161 -0
- package/dist/tests/application/use-cases/flush-buffers.use-case.spec.d.ts +1 -0
- package/dist/tests/application/use-cases/flush-buffers.use-case.spec.js +38 -0
- package/dist/tests/application/use-cases/get-logs.use-case.spec.d.ts +1 -0
- package/dist/tests/application/use-cases/get-logs.use-case.spec.js +114 -0
- package/dist/tests/application/use-cases/save-log.use-case.spec.d.ts +1 -0
- package/dist/tests/application/use-cases/save-log.use-case.spec.js +138 -0
- package/dist/tests/domain/services/log-level.service.spec.d.ts +1 -0
- package/dist/tests/domain/services/log-level.service.spec.js +68 -0
- package/dist/tests/domain/services/normalize-message.spec.d.ts +1 -0
- package/dist/tests/domain/services/normalize-message.spec.js +83 -0
- package/dist/tests/domain/services/pii-redactor.spec.d.ts +1 -0
- package/dist/tests/domain/services/pii-redactor.spec.js +170 -0
- package/dist/tests/domain/services/to-pii-regex.spec.d.ts +1 -0
- package/dist/tests/domain/services/to-pii-regex.spec.js +82 -0
- package/dist/tests/infrastructure/services/datasource.service.spec.d.ts +1 -0
- package/dist/tests/infrastructure/services/datasource.service.spec.js +128 -0
- package/dist/tests/test-utils/create-pii-redactor-mock.d.ts +5 -0
- package/dist/tests/test-utils/create-pii-redactor-mock.js +10 -0
- package/install.md +367 -0
- package/package.json +33 -10
- package/dist/Composite/index.d.ts +0 -9
- package/dist/Composite/index.js +0 -23
- package/dist/Factory/index.d.ts +0 -5
- package/dist/Factory/index.js +0 -23
- package/dist/config/index.d.ts +0 -2
- package/dist/config/interfaces/index.d.ts +0 -67
- package/dist/config/types/index.d.ts +0 -10
- package/dist/config/types/index.js +0 -13
- package/dist/domain/services/index.d.ts +0 -1
- package/dist/domain/services/pii-redactor.d.ts +0 -27
- package/dist/domain/services/pii-redactor.js +0 -139
- package/dist/index.d.ts +0 -4
- package/dist/interfaces/index.d.ts +0 -35
- package/dist/interfaces/index.js +0 -13
- package/dist/presentation/factory/index.js +0 -74
- package/dist/presentation/index.d.ts +0 -1
- /package/dist/{domain → src/infrastructure}/index.d.ts +0 -0
- /package/dist/{domain → src/infrastructure}/index.js +0 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PiiRedactorExample = void 0;
|
|
4
|
+
const services_1 = require("../src/domain/services");
|
|
5
|
+
class PiiRedactorExample {
|
|
6
|
+
static Main() {
|
|
7
|
+
console.log("=== 🔐 Ejemplo de uso: PiiRedactor ===\n");
|
|
8
|
+
// -----------------------------------------------------------------------
|
|
9
|
+
// 1️⃣ Definir patrones PII (emails, teléfonos, tarjetas)
|
|
10
|
+
// -----------------------------------------------------------------------
|
|
11
|
+
const patterns = [
|
|
12
|
+
{
|
|
13
|
+
pattern: "[\\w.-]+@[\\w.-]+\\.[A-Za-z]{2,}",
|
|
14
|
+
replaceWith: "[EMAIL]",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
pattern: "\\b\\d{10}\\b", // teléfonos de 10 dígitos
|
|
18
|
+
replaceWith: "[PHONE]",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
pattern: "\\b\\d{4}-\\d{4}-\\d{4}-\\d{4}\\b", // tarjeta simple
|
|
22
|
+
replaceWith: "[CARD]",
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
const options = {
|
|
26
|
+
enabled: true,
|
|
27
|
+
deep: true,
|
|
28
|
+
patterns,
|
|
29
|
+
whitelistKeys: ["publicInfo"],
|
|
30
|
+
blacklistKeys: ["password", "token"],
|
|
31
|
+
};
|
|
32
|
+
const redactor = new services_1.PiiRedactor(options);
|
|
33
|
+
// -----------------------------------------------------------------------
|
|
34
|
+
// 2️⃣ Redactar un string plano
|
|
35
|
+
// -----------------------------------------------------------------------
|
|
36
|
+
const rawText = "Usuario juan@example.com pagó con tarjeta 4111-1111-1111-1111 y llamó desde 0987654321";
|
|
37
|
+
const redactedText = redactor.redact(rawText);
|
|
38
|
+
console.log("→ String con PII:");
|
|
39
|
+
console.log(" Entrada :", rawText);
|
|
40
|
+
console.log(" Salida :", redactedText, "\n");
|
|
41
|
+
// -----------------------------------------------------------------------
|
|
42
|
+
// 3️⃣ Redactar un objeto anidado (deep=true)
|
|
43
|
+
// -----------------------------------------------------------------------
|
|
44
|
+
const rawObject = {
|
|
45
|
+
userId: 123,
|
|
46
|
+
email: "cliente@test.com",
|
|
47
|
+
phone: "0987654321",
|
|
48
|
+
password: "super-secret-password",
|
|
49
|
+
token: "eyJhbGciOi...",
|
|
50
|
+
publicInfo: "Este campo debe permanecer intacto 12345",
|
|
51
|
+
profile: {
|
|
52
|
+
address: "Calle Falsa 123",
|
|
53
|
+
contact: {
|
|
54
|
+
altEmail: "otro@test.com",
|
|
55
|
+
altPhone: "0999999999",
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
payments: [
|
|
59
|
+
{
|
|
60
|
+
card: "4111-1111-1111-1111",
|
|
61
|
+
amount: "150",
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
const clonedForComparison = JSON.parse(JSON.stringify(rawObject));
|
|
66
|
+
const redactedObject = redactor.redact(rawObject);
|
|
67
|
+
console.log("→ Objeto con PII (deep=true):");
|
|
68
|
+
console.log(" Entrada (original):");
|
|
69
|
+
console.log(JSON.stringify(clonedForComparison, null, 2));
|
|
70
|
+
console.log("\n Salida (redactado):");
|
|
71
|
+
console.log(JSON.stringify(redactedObject, null, 2));
|
|
72
|
+
console.log("\n Verificación (no mutado):");
|
|
73
|
+
console.log(" ¿Original === Clonado? ", JSON.stringify(rawObject) === JSON.stringify(clonedForComparison)
|
|
74
|
+
? "✅ Sin mutación visible"
|
|
75
|
+
: "⚠ Cambió (revisar implementación)");
|
|
76
|
+
console.log();
|
|
77
|
+
// -----------------------------------------------------------------------
|
|
78
|
+
// 4️⃣ Demostración de whitelistKeys y blacklistKeys
|
|
79
|
+
// -----------------------------------------------------------------------
|
|
80
|
+
console.log("→ Comportamiento con whitelist / blacklist:\n");
|
|
81
|
+
console.log(" - whitelistKeys: publicInfo (no se toca)");
|
|
82
|
+
console.log(" - blacklistKeys: password, token (se fuerza [REDACTED])\n");
|
|
83
|
+
console.log(" Campo publicInfo :", redactedObject.publicInfo);
|
|
84
|
+
console.log(" Campo password :", redactedObject.password);
|
|
85
|
+
console.log(" Campo token :", redactedObject.token, "\n");
|
|
86
|
+
// -----------------------------------------------------------------------
|
|
87
|
+
// 5️⃣ Actualizar opciones en caliente (updateOptions)
|
|
88
|
+
// -----------------------------------------------------------------------
|
|
89
|
+
console.log("→ Actualizando opciones en caliente (updateOptions):\n");
|
|
90
|
+
redactor.updateOptions({
|
|
91
|
+
enabled: true,
|
|
92
|
+
deep: false, // ahora no bajamos a objetos anidados
|
|
93
|
+
patterns: [
|
|
94
|
+
{
|
|
95
|
+
pattern: "\\d+",
|
|
96
|
+
replaceWith: "[NUM]",
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
});
|
|
100
|
+
const afterUpdate = redactor.redact({
|
|
101
|
+
level1: {
|
|
102
|
+
innerCode: "12345",
|
|
103
|
+
},
|
|
104
|
+
topLevel: "Código 999",
|
|
105
|
+
});
|
|
106
|
+
console.log(" Entrada:");
|
|
107
|
+
console.log(JSON.stringify({
|
|
108
|
+
level1: { innerCode: "12345" },
|
|
109
|
+
topLevel: "Código 999",
|
|
110
|
+
}, null, 2));
|
|
111
|
+
console.log("\n Salida con deep=false y patrón \\d+ → [NUM]:");
|
|
112
|
+
console.log(JSON.stringify(afterUpdate, null, 2));
|
|
113
|
+
console.log("\n Observa que 'topLevel' se redactor, pero 'level1.innerCode' no.");
|
|
114
|
+
// -----------------------------------------------------------------------
|
|
115
|
+
// 6️⃣ Desactivar el redactor (enabled=false)
|
|
116
|
+
// -----------------------------------------------------------------------
|
|
117
|
+
redactor.updateOptions({ enabled: false });
|
|
118
|
+
const disabledResult = redactor.redact("Email test2@example.com y teléfono 0912345678");
|
|
119
|
+
console.log("\n→ Redactor desactivado (enabled=false):");
|
|
120
|
+
console.log(" Salida debe ser igual a la entrada:");
|
|
121
|
+
console.log(" Resultado:", disabledResult, "\n");
|
|
122
|
+
console.log("=== ✔ Fin del ejemplo PiiRedactor ===");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
exports.PiiRedactorExample = PiiRedactorExample;
|
|
126
|
+
// Ejecución directa: ts-node / tsx examples/pii-redactor.example.ts
|
|
127
|
+
if (require.main === module) {
|
|
128
|
+
PiiRedactorExample.Main();
|
|
129
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SaveLogUseCaseExample = void 0;
|
|
4
|
+
const use_cases_1 = require("../src/application/use-cases");
|
|
5
|
+
const value_objects_1 = require("../src/domain/value-objects");
|
|
6
|
+
// -----------------------------------------------------------------------------
|
|
7
|
+
// 1️⃣ Implementación simple de un IPiiRedactor con PII de ejemplo
|
|
8
|
+
// - Redacta emails, tarjetas y teléfonos en strings
|
|
9
|
+
// - Aplica redacción a strings dentro de objetos (meta) de forma superficial
|
|
10
|
+
// -----------------------------------------------------------------------------
|
|
11
|
+
class SimplePiiRedactor {
|
|
12
|
+
redact(value) {
|
|
13
|
+
if (typeof value === "string") {
|
|
14
|
+
return this.redactString(value);
|
|
15
|
+
}
|
|
16
|
+
if (value && typeof value === "object") {
|
|
17
|
+
// redacción superficial de propiedades string
|
|
18
|
+
const clone = Array.isArray(value)
|
|
19
|
+
? [...value]
|
|
20
|
+
: { ...value };
|
|
21
|
+
for (const key of Object.keys(clone)) {
|
|
22
|
+
const v = clone[key];
|
|
23
|
+
if (typeof v === "string") {
|
|
24
|
+
clone[key] = this.redactString(v);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return clone;
|
|
28
|
+
}
|
|
29
|
+
// otros tipos se devuelven tal cual
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
// Opcional: podrías implementar updateOptions si quieres hacerla configurable
|
|
33
|
+
updateOptions() { }
|
|
34
|
+
redactString(input) {
|
|
35
|
+
return (input
|
|
36
|
+
// tarjetas de crédito (muy simple)
|
|
37
|
+
.replace(/\b\d{4}-\d{4}-\d{4}-\d{4}\b/g, "****-****-****-****")
|
|
38
|
+
// emails
|
|
39
|
+
.replace(/[\w.-]+@[\w.-]+/g, "***@***")
|
|
40
|
+
// teléfonos simples (10 dígitos)
|
|
41
|
+
.replace(/\b\d{10}\b/g, "**********"));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// -----------------------------------------------------------------------------
|
|
45
|
+
// 2️⃣ Implementación de un ILogDatasource en memoria con soporte de filtros
|
|
46
|
+
// - save: guarda en un array interno
|
|
47
|
+
// - find: aplica IGetLogsFilterProps (levelMin, since, until, query, limit, offset)
|
|
48
|
+
// -----------------------------------------------------------------------------
|
|
49
|
+
class InMemoryLogDatasource {
|
|
50
|
+
constructor() {
|
|
51
|
+
this.name = "in-memory";
|
|
52
|
+
this.store = [];
|
|
53
|
+
}
|
|
54
|
+
async save(log) {
|
|
55
|
+
this.store.push(log);
|
|
56
|
+
}
|
|
57
|
+
async find(filter) {
|
|
58
|
+
let results = [...this.store];
|
|
59
|
+
if (filter?.levelMin !== undefined) {
|
|
60
|
+
results = results.filter((log) => log.level >= filter.levelMin);
|
|
61
|
+
}
|
|
62
|
+
if (filter?.since !== undefined) {
|
|
63
|
+
results = results.filter((log) => log.timestamp >= filter.since);
|
|
64
|
+
}
|
|
65
|
+
if (filter?.until !== undefined) {
|
|
66
|
+
results = results.filter((log) => log.timestamp <= filter.until);
|
|
67
|
+
}
|
|
68
|
+
if (filter?.query) {
|
|
69
|
+
const q = filter.query.toLowerCase();
|
|
70
|
+
results = results.filter((log) => {
|
|
71
|
+
if (typeof log.message === "string") {
|
|
72
|
+
return log.message.toLowerCase().includes(q);
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
// paginación simple
|
|
78
|
+
const offset = filter?.offset ?? 0;
|
|
79
|
+
const limit = filter?.limit ?? results.length;
|
|
80
|
+
return results.slice(offset, offset + limit);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// -----------------------------------------------------------------------------
|
|
84
|
+
// 3️⃣ Ejemplo de uso real de SaveLogUseCase
|
|
85
|
+
// - Configura minLevel (filtro de entrada)
|
|
86
|
+
// - Usa PII redactor en message + meta
|
|
87
|
+
// - Demuestra búsquedas filtradas
|
|
88
|
+
// -----------------------------------------------------------------------------
|
|
89
|
+
class SaveLogUseCaseExample {
|
|
90
|
+
static async Main() {
|
|
91
|
+
console.log("\n=== 🧪 Ejemplo de uso: SaveLogUseCase ===\n");
|
|
92
|
+
// 1) Creamos datasource + redactor
|
|
93
|
+
const ds = new InMemoryLogDatasource();
|
|
94
|
+
const redactor = new SimplePiiRedactor();
|
|
95
|
+
// 2) Configuramos el caso de uso con un minLevel = INFO
|
|
96
|
+
const useCase = new use_cases_1.SaveLogUseCase({
|
|
97
|
+
ds,
|
|
98
|
+
minLevel: value_objects_1.LogLevel.INFO,
|
|
99
|
+
redactor,
|
|
100
|
+
});
|
|
101
|
+
console.log("📌 minLevel configurado en:", value_objects_1.LogLevel[value_objects_1.LogLevel.INFO], "\n");
|
|
102
|
+
// 3) Intentamos loggear algo por debajo del umbral (DEBUG → debe ser ignorado)
|
|
103
|
+
console.log("➖ Log DEBUG (debe SER IGNORADO por el filtro):");
|
|
104
|
+
await useCase.execute(value_objects_1.LogLevel.DEBUG, "Debug interno con detalles que no queremos en producción");
|
|
105
|
+
// 4) Log INFO simple, sin PII
|
|
106
|
+
console.log("\n➕ Log INFO (debe SER GUARDADO):");
|
|
107
|
+
await useCase.execute(value_objects_1.LogLevel.INFO, "Servicio iniciado correctamente");
|
|
108
|
+
// 5) Log ERROR con PII en message y meta
|
|
109
|
+
console.log("\n❌ Log ERROR con PII en message y meta (debe ser REDACTADO):");
|
|
110
|
+
const rawMessage = "Error al procesar pago con tarjeta 4111-1111-1111-1111 del usuario john.doe@example.com";
|
|
111
|
+
const metaConPii = {
|
|
112
|
+
userId: "123",
|
|
113
|
+
email: "john.doe@example.com",
|
|
114
|
+
card: "4111-1111-1111-1111",
|
|
115
|
+
phone: "0998765432",
|
|
116
|
+
};
|
|
117
|
+
await useCase.execute(value_objects_1.LogLevel.ERROR, rawMessage, metaConPii);
|
|
118
|
+
// 6) Log WARN con PII solo en meta
|
|
119
|
+
console.log("\n⚠ Log WARN con PII solo en meta:");
|
|
120
|
+
await useCase.execute(value_objects_1.LogLevel.WARN, "Intento de acceso sospechoso", {
|
|
121
|
+
ip: "192.168.0.10",
|
|
122
|
+
email: "evil.hacker@example.com",
|
|
123
|
+
});
|
|
124
|
+
// 7) Consultamos todos los logs con level >= INFO
|
|
125
|
+
console.log("\n📂 Recuperando logs con filtro: levelMin = INFO\n");
|
|
126
|
+
const allInfoOrHigher = await ds.find({
|
|
127
|
+
levelMin: value_objects_1.LogLevel.INFO,
|
|
128
|
+
});
|
|
129
|
+
console.log("➡ Resultado (level >= INFO):");
|
|
130
|
+
console.dir(allInfoOrHigher, { depth: 5 });
|
|
131
|
+
// 8) Consultamos solo errores que contengan la palabra "pago"
|
|
132
|
+
console.log("\n📂 Recuperando logs con filtro: levelMin = ERROR, query = 'pago'\n");
|
|
133
|
+
const errorPayments = await ds.find({
|
|
134
|
+
levelMin: value_objects_1.LogLevel.ERROR,
|
|
135
|
+
query: "pago",
|
|
136
|
+
});
|
|
137
|
+
console.log("➡ Resultado (ERROR + 'pago'):");
|
|
138
|
+
console.dir(errorPayments, { depth: 5 });
|
|
139
|
+
// 9) Consultamos logs con límite/paginación
|
|
140
|
+
console.log("\n📂 Recuperando máximo 2 logs (limit = 2):\n");
|
|
141
|
+
const limited = await ds.find({
|
|
142
|
+
levelMin: value_objects_1.LogLevel.INFO,
|
|
143
|
+
limit: 2,
|
|
144
|
+
});
|
|
145
|
+
console.log("➡ Resultado (primeros 2 logs):");
|
|
146
|
+
console.dir(limited, { depth: 5 });
|
|
147
|
+
console.log("\n✅ Ejemplo SaveLogUseCase finalizado.\n");
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
exports.SaveLogUseCaseExample = SaveLogUseCaseExample;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ToLogLevelExample = void 0;
|
|
4
|
+
const domain_1 = require("src/domain");
|
|
5
|
+
class ToLogLevelExample {
|
|
6
|
+
static Main() {
|
|
7
|
+
console.log("=== 🔎 Ejemplo de uso: toLogLevel ===\n");
|
|
8
|
+
// ------------------------------------------------------------------------
|
|
9
|
+
// 1️⃣ Conversión básica desde string
|
|
10
|
+
// ------------------------------------------------------------------------
|
|
11
|
+
console.log("→ Conversión desde strings:");
|
|
12
|
+
const str1 = (0, domain_1.toLogLevel)("debug");
|
|
13
|
+
const str2 = (0, domain_1.toLogLevel)("ERROR");
|
|
14
|
+
const str3 = (0, domain_1.toLogLevel)("unknown"); // fallback
|
|
15
|
+
console.log(` "debug" → ${str1}`);
|
|
16
|
+
console.log(` "ERROR" → ${str2}`);
|
|
17
|
+
console.log(` "unknown" → ${str3} (fallback)\n`);
|
|
18
|
+
// ------------------------------------------------------------------------
|
|
19
|
+
// 2️⃣ Conversión desde números
|
|
20
|
+
// ------------------------------------------------------------------------
|
|
21
|
+
console.log("→ Conversión desde números:");
|
|
22
|
+
const num1 = (0, domain_1.toLogLevel)(domain_1.LogLevel.WARN);
|
|
23
|
+
const num2 = (0, domain_1.toLogLevel)(999); // no existe → fallback
|
|
24
|
+
console.log(` LogLevel.WARN → ${num1}`);
|
|
25
|
+
console.log(` 999 → ${num2} (fallback)\n`);
|
|
26
|
+
// ------------------------------------------------------------------------
|
|
27
|
+
// 3️⃣ Uso del parámetro 'default'
|
|
28
|
+
// ------------------------------------------------------------------------
|
|
29
|
+
console.log("→ Uso de valor por defecto personalizado:");
|
|
30
|
+
const def1 = (0, domain_1.toLogLevel)(undefined, domain_1.LogLevel.FATAL);
|
|
31
|
+
const def2 = (0, domain_1.toLogLevel)("invalid", domain_1.LogLevel.DEBUG);
|
|
32
|
+
console.log(` undefined, default FATAL → ${def1}`);
|
|
33
|
+
console.log(` "invalid", default DEBUG → ${def2}\n`);
|
|
34
|
+
// ------------------------------------------------------------------------
|
|
35
|
+
// 4️⃣ Uso en un caso real (ejemplo típico)
|
|
36
|
+
// ------------------------------------------------------------------------
|
|
37
|
+
console.log("→ Caso real: leer LOG_LEVEL desde variables de entorno");
|
|
38
|
+
const rawEnvLogLevel = process.env.LOG_LEVEL; // ej: "warn"
|
|
39
|
+
const resolvedLevel = (0, domain_1.toLogLevel)(rawEnvLogLevel, domain_1.LogLevel.INFO);
|
|
40
|
+
console.log(` LOG_LEVEL raw: ${rawEnvLogLevel}`);
|
|
41
|
+
console.log(` LOG_LEVEL resolved: ${resolvedLevel}\n`);
|
|
42
|
+
console.log("=== ✔ Fin del ejemplo toLogLevel ===");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.ToLogLevelExample = ToLogLevelExample;
|
|
46
|
+
// Ejecutar si se ejecuta directamente con ts-node/tsx
|
|
47
|
+
if (require.main === module) {
|
|
48
|
+
ToLogLevelExample.Main();
|
|
49
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ToPiiRegexExample = void 0;
|
|
4
|
+
const services_1 = require("../src/domain/services");
|
|
5
|
+
class ToPiiRegexExample {
|
|
6
|
+
static Main() {
|
|
7
|
+
console.log("=== 🔍 Ejemplo de uso: toPiiRegex ===\n");
|
|
8
|
+
// -----------------------------------------------------------------------
|
|
9
|
+
// 1️⃣ Crear un regex para detectar números (por ejemplo montos o IDs)
|
|
10
|
+
// -----------------------------------------------------------------------
|
|
11
|
+
const digitsRule = {
|
|
12
|
+
pattern: "\\d+",
|
|
13
|
+
replaceWith: "[NUM]",
|
|
14
|
+
};
|
|
15
|
+
const digitsRegex = (0, services_1.toPiiRegex)(digitsRule);
|
|
16
|
+
console.log("→ Regla para números:");
|
|
17
|
+
console.log(" Pattern:", digitsRule.pattern);
|
|
18
|
+
console.log(" Flags:", digitsRegex.flags);
|
|
19
|
+
console.log(" Regex generado:", digitsRegex);
|
|
20
|
+
console.log(" Aplicación:", "Pedido 12345 procesado".replace(digitsRegex, digitsRule.replaceWith), "\n");
|
|
21
|
+
// -----------------------------------------------------------------------
|
|
22
|
+
// 2️⃣ Crear un regex para emails con flags personalizados
|
|
23
|
+
// -----------------------------------------------------------------------
|
|
24
|
+
const emailRule = {
|
|
25
|
+
pattern: "[\\w.-]+@[\\w.-]+\\.[A-Za-z]{2,}",
|
|
26
|
+
flags: "gi",
|
|
27
|
+
replaceWith: "[EMAIL]",
|
|
28
|
+
};
|
|
29
|
+
const emailRegex = (0, services_1.toPiiRegex)(emailRule);
|
|
30
|
+
console.log("→ Regla para emails:");
|
|
31
|
+
console.log(" Pattern:", emailRule.pattern);
|
|
32
|
+
console.log(" Flags:", emailRegex.flags);
|
|
33
|
+
console.log(" Regex generado:", emailRegex);
|
|
34
|
+
console.log(" Aplicación:", "Usuario juan@example.com inició sesión".replace(emailRegex, emailRule.replaceWith), "\n");
|
|
35
|
+
// -----------------------------------------------------------------------
|
|
36
|
+
// 3️⃣ Caso real: varias reglas aplicadas para redactor PII
|
|
37
|
+
// -----------------------------------------------------------------------
|
|
38
|
+
const rules = [
|
|
39
|
+
{
|
|
40
|
+
pattern: "\\d{10}", // teléfonos
|
|
41
|
+
replaceWith: "[PHONE]",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
pattern: "[\\w.-]+@[\\w.-]+\\.[A-Za-z]{2,}",
|
|
45
|
+
replaceWith: "[EMAIL]",
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
const sampleLog = "Cliente mario@test.com llamó desde 0987654321 para confirmar su pedido.";
|
|
49
|
+
let redacted = sampleLog;
|
|
50
|
+
for (const rule of rules) {
|
|
51
|
+
const regex = (0, services_1.toPiiRegex)(rule);
|
|
52
|
+
redacted = redacted.replace(regex, rule.replaceWith);
|
|
53
|
+
}
|
|
54
|
+
console.log("→ Caso real con múltiples reglas:");
|
|
55
|
+
console.log(" Entrada:", sampleLog);
|
|
56
|
+
console.log(" Salida:", redacted, "\n");
|
|
57
|
+
// -----------------------------------------------------------------------
|
|
58
|
+
// 4️⃣ Caso con patrón inválido (fallback seguro /$a/)
|
|
59
|
+
// -----------------------------------------------------------------------
|
|
60
|
+
const invalidRule = {
|
|
61
|
+
pattern: "[unclosed", // inválido
|
|
62
|
+
replaceWith: "***",
|
|
63
|
+
};
|
|
64
|
+
const invalidRegex = (0, services_1.toPiiRegex)(invalidRule);
|
|
65
|
+
console.log("→ Patrón inválido, debería producir fallback /$a/:");
|
|
66
|
+
console.log(" Regex generado:", invalidRegex);
|
|
67
|
+
console.log(" Hace match?:", invalidRegex.test("cualquier cosa"), "\n");
|
|
68
|
+
console.log("=== ✔ Fin del ejemplo toPiiRegex ===");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.ToPiiRegexExample = ToPiiRegexExample;
|
|
72
|
+
// Permite ejecución directa con ts-node / tsx
|
|
73
|
+
if (require.main === module) {
|
|
74
|
+
ToPiiRegexExample.Main();
|
|
75
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ICreateLoggerOptions, ILogDatasource, ILogger } from "
|
|
1
|
+
import { ICreateLoggerOptions, ILogDatasource, ILogger } from "../../domain/ports";
|
|
2
2
|
export declare function createLogger(ds: ILogDatasource, opts?: ICreateLoggerOptions): ILogger;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createLogger = createLogger;
|
|
4
|
+
const services_1 = require("../../domain/services");
|
|
5
|
+
const value_objects_1 = require("../../domain/value-objects");
|
|
6
|
+
const use_cases_1 = require("../use-cases");
|
|
7
|
+
// Factoría de logger. Encapsula composición de casos de uso y servicios
|
|
8
|
+
function createLogger(ds, opts = {}) {
|
|
9
|
+
// Resolve minLevel con un default razonable (INFO)
|
|
10
|
+
const minLevel = opts.minLevel ?? value_objects_1.LogLevel.INFO;
|
|
11
|
+
// Mantén compatibilidad con redactPII
|
|
12
|
+
const piiEnabled = opts.pii?.enabled ?? opts.redactPII ?? false;
|
|
13
|
+
const redactor = new services_1.PiiRedactor({ enabled: piiEnabled, ...opts.pii });
|
|
14
|
+
const save = new use_cases_1.SaveLogUseCase({ ds, minLevel, redactor });
|
|
15
|
+
const flushUC = new use_cases_1.FlushBuffersUseCase(ds);
|
|
16
|
+
// Helper emisor; si en el futuro se necesita encolar, aquí es el lugar
|
|
17
|
+
const emit = (lvl, message, meta) => save.execute(lvl, message, meta);
|
|
18
|
+
return {
|
|
19
|
+
trace: (m, meta) => emit(value_objects_1.LogLevel.TRACE, m, meta),
|
|
20
|
+
debug: (m, meta) => emit(value_objects_1.LogLevel.DEBUG, m, meta),
|
|
21
|
+
info: (m, meta) => emit(value_objects_1.LogLevel.INFO, m, meta),
|
|
22
|
+
warn: (m, meta) => emit(value_objects_1.LogLevel.WARN, m, meta),
|
|
23
|
+
error: (m, meta) => emit(value_objects_1.LogLevel.ERROR, m, meta),
|
|
24
|
+
fatal: (m, meta) => emit(value_objects_1.LogLevel.FATAL, m, meta),
|
|
25
|
+
// Gestión de ciclo de vida → delega en caso de uso / puerto
|
|
26
|
+
flush: () => flushUC.execute(),
|
|
27
|
+
dispose: () => ds.dispose?.() ?? Promise.resolve(),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./logger.factory";
|
|
@@ -14,5 +14,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./
|
|
18
|
-
__exportStar(require("./types"), exports);
|
|
17
|
+
__exportStar(require("./logger.factory"), exports);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ILoggerFactoryConfig, ILoggerService } from "../../domain/ports";
|
|
2
|
+
/**
|
|
3
|
+
* Factory principal de @jmlq/logger.
|
|
4
|
+
* Se encarga de:
|
|
5
|
+
* - Componer datasources (fan-out si hay varios)
|
|
6
|
+
* - Construir el redactor de PII
|
|
7
|
+
* - Instanciar y conectar los casos de uso
|
|
8
|
+
* - Exponer un servicio de logger de alto nivel
|
|
9
|
+
*/
|
|
10
|
+
export declare class LoggerFactory {
|
|
11
|
+
static create(config: ILoggerFactoryConfig): ILoggerService;
|
|
12
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LoggerFactory = void 0;
|
|
4
|
+
const value_objects_1 = require("../../domain/value-objects");
|
|
5
|
+
const pii_redactor_service_1 = require("../../domain/services/pii-redactor.service");
|
|
6
|
+
const datasource_service_1 = require("../../infrastructure/services/datasource.service");
|
|
7
|
+
const use_cases_1 = require("../use-cases");
|
|
8
|
+
/**
|
|
9
|
+
* Factory principal de @jmlq/logger.
|
|
10
|
+
* Se encarga de:
|
|
11
|
+
* - Componer datasources (fan-out si hay varios)
|
|
12
|
+
* - Construir el redactor de PII
|
|
13
|
+
* - Instanciar y conectar los casos de uso
|
|
14
|
+
* - Exponer un servicio de logger de alto nivel
|
|
15
|
+
*/
|
|
16
|
+
class LoggerFactory {
|
|
17
|
+
static create(config) {
|
|
18
|
+
// 1) Normalizar config
|
|
19
|
+
const minLevel = config.minLevel ?? value_objects_1.LogLevel.INFO;
|
|
20
|
+
const datasources = Array.isArray(config.datasources)
|
|
21
|
+
? config.datasources
|
|
22
|
+
: [config.datasources];
|
|
23
|
+
// 2) Componer datasource (si hay varios) con DataSourceService
|
|
24
|
+
const ds = datasources.length === 1
|
|
25
|
+
? datasources[0]
|
|
26
|
+
: new datasource_service_1.DataSourceService(datasources);
|
|
27
|
+
// 3) Crear/usar redactor de PII
|
|
28
|
+
const redactor = config.redactor ?? new pii_redactor_service_1.PiiRedactor(config.redactorOptions);
|
|
29
|
+
// 4) Construir casos de uso de Application
|
|
30
|
+
const saveLogUseCase = new use_cases_1.SaveLogUseCase({
|
|
31
|
+
ds,
|
|
32
|
+
minLevel,
|
|
33
|
+
redactor,
|
|
34
|
+
});
|
|
35
|
+
const getLogsUseCase = new use_cases_1.GetLogsUseCase(ds);
|
|
36
|
+
const flushBuffersUseCase = new use_cases_1.FlushBuffersUseCase(ds);
|
|
37
|
+
// 5) Construir facade de servicio de logging
|
|
38
|
+
const service = {
|
|
39
|
+
// Método genérico de logging
|
|
40
|
+
async log(level, message, meta) {
|
|
41
|
+
await saveLogUseCase.execute(level, message, meta);
|
|
42
|
+
},
|
|
43
|
+
// Helpers por nivel
|
|
44
|
+
trace(message, meta) {
|
|
45
|
+
return saveLogUseCase.execute(value_objects_1.LogLevel.TRACE, message, meta);
|
|
46
|
+
},
|
|
47
|
+
debug(message, meta) {
|
|
48
|
+
return saveLogUseCase.execute(value_objects_1.LogLevel.DEBUG, message, meta);
|
|
49
|
+
},
|
|
50
|
+
info(message, meta) {
|
|
51
|
+
return saveLogUseCase.execute(value_objects_1.LogLevel.INFO, message, meta);
|
|
52
|
+
},
|
|
53
|
+
warn(message, meta) {
|
|
54
|
+
return saveLogUseCase.execute(value_objects_1.LogLevel.WARN, message, meta);
|
|
55
|
+
},
|
|
56
|
+
error(message, meta) {
|
|
57
|
+
return saveLogUseCase.execute(value_objects_1.LogLevel.ERROR, message, meta);
|
|
58
|
+
},
|
|
59
|
+
fatal(message, meta) {
|
|
60
|
+
return saveLogUseCase.execute(value_objects_1.LogLevel.FATAL, message, meta);
|
|
61
|
+
},
|
|
62
|
+
// Lectura de logs con filtros
|
|
63
|
+
async getLogs(filter) {
|
|
64
|
+
return getLogsUseCase.execute(filter);
|
|
65
|
+
},
|
|
66
|
+
// Flush explícito (si el datasource lo soporta)
|
|
67
|
+
async flush() {
|
|
68
|
+
await flushBuffersUseCase.execute();
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
return service;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.LoggerFactory = LoggerFactory;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FlushBuffersUseCase = void 0;
|
|
4
|
+
class FlushBuffersUseCase {
|
|
5
|
+
constructor(ds) {
|
|
6
|
+
this.ds = ds;
|
|
7
|
+
}
|
|
8
|
+
async execute() {
|
|
9
|
+
// flush es opcional; si no está implementado, no hace nada
|
|
10
|
+
await this.ds.flush?.();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.FlushBuffersUseCase = FlushBuffersUseCase;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ILogDatasource } from "../../domain/ports";
|
|
2
|
+
import { IGetLogsFilterProps } from "../../domain/request";
|
|
3
|
+
import { ILogResponse } from "../../domain/response";
|
|
4
|
+
export declare class GetLogsUseCase {
|
|
5
|
+
private readonly ds;
|
|
6
|
+
constructor(ds: ILogDatasource);
|
|
7
|
+
execute(filter?: IGetLogsFilterProps): Promise<ILogResponse[]>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GetLogsUseCase = void 0;
|
|
4
|
+
class GetLogsUseCase {
|
|
5
|
+
constructor(ds) {
|
|
6
|
+
this.ds = ds;
|
|
7
|
+
}
|
|
8
|
+
async execute(filter) {
|
|
9
|
+
if (!this.ds.find)
|
|
10
|
+
return []; // si el datasource no lo soporta, retorna vacío
|
|
11
|
+
// Sanitiza límites (evita valores negativos o absurdos)
|
|
12
|
+
const safe = filter
|
|
13
|
+
? {
|
|
14
|
+
...filter,
|
|
15
|
+
limit: filter.limit && filter.limit > 0
|
|
16
|
+
? Math.min(filter.limit, 5000)
|
|
17
|
+
: undefined,
|
|
18
|
+
offset: filter.offset && filter.offset >= 0 ? filter.offset : undefined,
|
|
19
|
+
}
|
|
20
|
+
: undefined;
|
|
21
|
+
return this.ds.find(safe);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.GetLogsUseCase = GetLogsUseCase;
|
|
@@ -0,0 +1,19 @@
|
|
|
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("./save-log.use-case"), exports);
|
|
18
|
+
__exportStar(require("./get-logs.use-case"), exports);
|
|
19
|
+
__exportStar(require("./flush-buffers.use-case"), exports);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ISaveLogProps } from "../../domain/request";
|
|
2
|
+
import { LogMessage } from "../../domain/types";
|
|
3
|
+
import { LogLevel } from "../../domain/value-objects";
|
|
4
|
+
export declare class SaveLogUseCase {
|
|
5
|
+
private readonly props;
|
|
6
|
+
constructor(props: ISaveLogProps);
|
|
7
|
+
execute(level: LogLevel, message: LogMessage, meta?: unknown): Promise<void>;
|
|
8
|
+
}
|