logixia 1.10.2 → 1.10.3
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/dist/.tsbuildinfo +1 -1
- package/dist/index.d.mts +5 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +75 -33
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +75 -33
- package/dist/index.mjs.map +1 -1
- package/dist/logitron-logger.module-B8NklSC4.d.mts.map +1 -1
- package/dist/{logitron-logger.module-Bt_Jei1V.mjs → logitron-logger.module-BBC9nO5q.mjs} +118 -37
- package/dist/logitron-logger.module-BBC9nO5q.mjs.map +1 -0
- package/dist/logitron-logger.module-BLT1y5Iq.d.ts.map +1 -1
- package/dist/{logitron-logger.module-bJ1hGhaL.js → logitron-logger.module-Dlf5GwJ9.js} +118 -37
- package/dist/logitron-logger.module-Dlf5GwJ9.js.map +1 -0
- package/dist/middleware.d.mts.map +1 -1
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +4 -3
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +4 -3
- package/dist/middleware.mjs.map +1 -1
- package/dist/nest.d.mts.map +1 -1
- package/dist/nest.d.ts.map +1 -1
- package/dist/nest.js +2 -2
- package/dist/nest.mjs +2 -2
- package/dist/{transport.manager-zgEZCJhR.js → transport.manager-B9LF9uDd.js} +130 -56
- package/dist/transport.manager-B9LF9uDd.js.map +1 -0
- package/dist/{transport.manager-CaL4XuLD.mjs → transport.manager-Cij_sA-b.mjs} +128 -56
- package/dist/transport.manager-Cij_sA-b.mjs.map +1 -0
- package/dist/transports.d.mts +41 -2
- package/dist/transports.d.mts.map +1 -1
- package/dist/transports.d.ts +41 -2
- package/dist/transports.d.ts.map +1 -1
- package/dist/transports.js +1 -1
- package/dist/transports.mjs +1 -1
- package/package.json +1 -1
- package/dist/logitron-logger.module-Bt_Jei1V.mjs.map +0 -1
- package/dist/logitron-logger.module-bJ1hGhaL.js.map +0 -1
- package/dist/transport.manager-CaL4XuLD.mjs.map +0 -1
- package/dist/transport.manager-zgEZCJhR.js.map +0 -1
|
@@ -3,7 +3,9 @@ import { EventEmitter } from "node:events";
|
|
|
3
3
|
import * as readline from "node:readline";
|
|
4
4
|
import * as fs from "node:fs";
|
|
5
5
|
import * as path from "node:path";
|
|
6
|
+
import { pipeline } from "node:stream/promises";
|
|
6
7
|
import { promisify } from "node:util";
|
|
8
|
+
import { createGzip } from "node:zlib";
|
|
7
9
|
|
|
8
10
|
//#region rolldown:runtime
|
|
9
11
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
@@ -21,28 +23,36 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
21
23
|
* helpers instead so that internal output can be silenced in tests by setting
|
|
22
24
|
* the LOGIXIA_SILENT_INTERNAL=1 environment variable.
|
|
23
25
|
*/
|
|
24
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Read the silence flag on each call rather than caching it at import time, so
|
|
28
|
+
* setting LOGIXIA_SILENT_INTERNAL=1 AFTER the module is first imported (e.g. in
|
|
29
|
+
* a test setup file) still takes effect — the documented test-silencing
|
|
30
|
+
* behavior was previously unreliable because the value was frozen at load.
|
|
31
|
+
*/
|
|
32
|
+
function isSilent() {
|
|
33
|
+
return process.env.LOGIXIA_SILENT_INTERNAL === "1";
|
|
34
|
+
}
|
|
25
35
|
/**
|
|
26
36
|
* Emit an internal debug/info message to stderr.
|
|
27
37
|
* Use for field-enable/disable notifications that a developer might want to see
|
|
28
38
|
* during development but should not appear in production log streams.
|
|
29
39
|
*/
|
|
30
40
|
function internalLog(message) {
|
|
31
|
-
if (!
|
|
41
|
+
if (!isSilent()) process.stderr.write(`[logixia] ${message}\n`);
|
|
32
42
|
}
|
|
33
43
|
/**
|
|
34
44
|
* Emit an internal warning to stderr.
|
|
35
45
|
* Use when something is misconfigured but logixia can continue operating.
|
|
36
46
|
*/
|
|
37
47
|
function internalWarn(message) {
|
|
38
|
-
if (!
|
|
48
|
+
if (!isSilent()) process.stderr.write(`[logixia:warn] ${message}\n`);
|
|
39
49
|
}
|
|
40
50
|
/**
|
|
41
51
|
* Emit an internal error to stderr.
|
|
42
52
|
* Use when a transport write fails or a serious internal error occurs.
|
|
43
53
|
*/
|
|
44
54
|
function internalError(message, error) {
|
|
45
|
-
if (!
|
|
55
|
+
if (!isSilent()) {
|
|
46
56
|
let errStr = "";
|
|
47
57
|
if (error instanceof Error) errStr = ` — ${error.message}`;
|
|
48
58
|
else if (error != null) errStr = ` — ${String(error)}`;
|
|
@@ -72,6 +82,7 @@ function internalError(message, error) {
|
|
|
72
82
|
* `String(value)` for circular refs / values without a stringifier.
|
|
73
83
|
*/
|
|
74
84
|
function safeToString(value) {
|
|
85
|
+
var _constructor;
|
|
75
86
|
if (typeof value === "string") return value;
|
|
76
87
|
if (value === void 0 || value === null) return "";
|
|
77
88
|
if (value instanceof Error) return value.message;
|
|
@@ -79,11 +90,10 @@ function safeToString(value) {
|
|
|
79
90
|
if (typeof value === "symbol") return value.toString();
|
|
80
91
|
if (typeof value === "function") return `[Function: ${value.name || "anonymous"}]`;
|
|
81
92
|
try {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
93
|
+
const json = JSON.stringify(value);
|
|
94
|
+
if (json !== void 0) return json;
|
|
95
|
+
} catch {}
|
|
96
|
+
return `[${((_constructor = value.constructor) === null || _constructor === void 0 ? void 0 : _constructor.name) ?? "object"}]`;
|
|
87
97
|
}
|
|
88
98
|
|
|
89
99
|
//#endregion
|
|
@@ -216,7 +226,6 @@ var DatabaseTransport = class {
|
|
|
216
226
|
this.config = config;
|
|
217
227
|
this.name = "database";
|
|
218
228
|
this.batch = [];
|
|
219
|
-
this.isFlushing = false;
|
|
220
229
|
this.isConnected = false;
|
|
221
230
|
this.batchSize = config.batchSize || 100;
|
|
222
231
|
this.flushInterval = config.flushInterval || 5e3;
|
|
@@ -233,33 +242,44 @@ var DatabaseTransport = class {
|
|
|
233
242
|
this.batch.push(entry);
|
|
234
243
|
}
|
|
235
244
|
async flush() {
|
|
236
|
-
if (this.
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
245
|
+
if (!this.flushPromise) this.flushPromise = this.drain().finally(() => {
|
|
246
|
+
this.flushPromise = void 0;
|
|
247
|
+
});
|
|
248
|
+
await this.flushPromise;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Drains the batch to the database one snapshot at a time. The current batch
|
|
252
|
+
* is detached SYNCHRONOUSLY before awaiting the write, so entries appended by
|
|
253
|
+
* concurrent write() calls land in a fresh array and are never written twice.
|
|
254
|
+
* On write failure the snapshot is restored to the front of the batch for the
|
|
255
|
+
* next flush cycle and the loop stops, so a persistently failing DB does not
|
|
256
|
+
* hot-spin retrying the same entries.
|
|
257
|
+
*/
|
|
258
|
+
async drain() {
|
|
259
|
+
while (this.batch.length > 0) {
|
|
260
|
+
const entriesToFlush = this.batch;
|
|
261
|
+
this.batch = [];
|
|
262
|
+
try {
|
|
263
|
+
switch (this.config.type) {
|
|
264
|
+
case "mongodb":
|
|
265
|
+
await this.flushToMongoDB(entriesToFlush);
|
|
266
|
+
break;
|
|
267
|
+
case "postgresql":
|
|
268
|
+
await this.flushToPostgreSQL(entriesToFlush);
|
|
269
|
+
break;
|
|
270
|
+
case "mysql":
|
|
271
|
+
await this.flushToMySQL(entriesToFlush);
|
|
272
|
+
break;
|
|
273
|
+
case "sqlite":
|
|
274
|
+
await this.flushToSQLite(entriesToFlush);
|
|
275
|
+
break;
|
|
276
|
+
default: throw new Error(`Unsupported database type: ${this.config.type}`);
|
|
277
|
+
}
|
|
278
|
+
} catch (error) {
|
|
279
|
+
internalError("Database flush error", error);
|
|
280
|
+
this.batch.unshift(...entriesToFlush);
|
|
281
|
+
throw error;
|
|
256
282
|
}
|
|
257
|
-
} catch (error) {
|
|
258
|
-
internalError("Database flush error", error);
|
|
259
|
-
this.batch.unshift(...entriesToFlush);
|
|
260
|
-
throw error;
|
|
261
|
-
} finally {
|
|
262
|
-
this.isFlushing = false;
|
|
263
283
|
}
|
|
264
284
|
}
|
|
265
285
|
async isReady() {
|
|
@@ -272,7 +292,10 @@ var DatabaseTransport = class {
|
|
|
272
292
|
}
|
|
273
293
|
async connect() {
|
|
274
294
|
if (this.connectionPromise) return this.connectionPromise;
|
|
275
|
-
this.connectionPromise = this.establishConnection()
|
|
295
|
+
this.connectionPromise = this.establishConnection().catch((error) => {
|
|
296
|
+
this.connectionPromise = void 0;
|
|
297
|
+
throw error;
|
|
298
|
+
});
|
|
276
299
|
return this.connectionPromise;
|
|
277
300
|
}
|
|
278
301
|
async establishConnection() {
|
|
@@ -503,8 +526,17 @@ var DatabaseTransport = class {
|
|
|
503
526
|
}, this.flushInterval);
|
|
504
527
|
}
|
|
505
528
|
async close() {
|
|
506
|
-
if (this.flushTimer)
|
|
507
|
-
|
|
529
|
+
if (this.flushTimer) {
|
|
530
|
+
clearInterval(this.flushTimer);
|
|
531
|
+
this.flushTimer = void 0;
|
|
532
|
+
}
|
|
533
|
+
const MAX_CLOSE_FLUSH_ATTEMPTS = 3;
|
|
534
|
+
for (let attempt = 0; attempt < MAX_CLOSE_FLUSH_ATTEMPTS && this.batch.length > 0; attempt += 1) try {
|
|
535
|
+
await this.flush();
|
|
536
|
+
} catch (error) {
|
|
537
|
+
internalError("Database flush during close failed; entries remain buffered", error);
|
|
538
|
+
}
|
|
539
|
+
if (this.batch.length > 0) internalError(`Database transport closing with ${this.batch.length} unflushed log entr${this.batch.length === 1 ? "y" : "ies"} after ${MAX_CLOSE_FLUSH_ATTEMPTS} attempts`);
|
|
508
540
|
if (this.connection) switch (this.config.type) {
|
|
509
541
|
case "mongodb":
|
|
510
542
|
await this.connection.close();
|
|
@@ -540,7 +572,8 @@ var DatabaseTransport = class {
|
|
|
540
572
|
var _result$rows, _result$;
|
|
541
573
|
const tableName = this.config.table || "logs";
|
|
542
574
|
const result = await this.connection.query(`SELECT COUNT(*) as count FROM ${tableName}`);
|
|
543
|
-
|
|
575
|
+
const rawCount = ((_result$rows = result.rows) === null || _result$rows === void 0 || (_result$rows = _result$rows[0]) === null || _result$rows === void 0 ? void 0 : _result$rows.count) ?? ((_result$ = result[0]) === null || _result$ === void 0 ? void 0 : _result$.count) ?? 0;
|
|
576
|
+
return Number(rawCount) || 0;
|
|
544
577
|
}
|
|
545
578
|
default: return 0;
|
|
546
579
|
}
|
|
@@ -583,23 +616,43 @@ var AnalyticsTransport = class {
|
|
|
583
616
|
}, this.config.flushInterval);
|
|
584
617
|
}
|
|
585
618
|
async flush() {
|
|
586
|
-
if (this.batch.length === 0) return;
|
|
587
|
-
const entriesToSend = [...this.batch];
|
|
588
|
-
this.batch = [];
|
|
589
619
|
if (this.batchTimer) {
|
|
590
620
|
clearTimeout(this.batchTimer);
|
|
591
|
-
|
|
621
|
+
this.batchTimer = void 0;
|
|
592
622
|
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
|
|
623
|
+
if (!this.flushPromise) this.flushPromise = this.drain().finally(() => {
|
|
624
|
+
this.flushPromise = void 0;
|
|
625
|
+
});
|
|
626
|
+
await this.flushPromise;
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Drains the batch to the provider one snapshot at a time. The batch is
|
|
630
|
+
* detached SYNCHRONOUSLY before awaiting sendBatch(), so entries appended by
|
|
631
|
+
* concurrent writes land in a fresh array and are never sent twice. On failure
|
|
632
|
+
* the snapshot is restored to the front of the batch for the next flush and
|
|
633
|
+
* the loop stops, so a failing provider does not hot-spin.
|
|
634
|
+
*/
|
|
635
|
+
async drain() {
|
|
636
|
+
while (this.batch.length > 0) {
|
|
637
|
+
const entriesToSend = this.batch;
|
|
638
|
+
this.batch = [];
|
|
639
|
+
try {
|
|
640
|
+
await this.sendBatch(entriesToSend);
|
|
641
|
+
} catch (error) {
|
|
642
|
+
internalError(`Analytics transport ${this.name} flush failed`, error);
|
|
643
|
+
this.batch.unshift(...entriesToSend);
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
598
646
|
}
|
|
599
647
|
}
|
|
600
648
|
async close() {
|
|
601
|
-
|
|
602
|
-
|
|
649
|
+
if (this.batchTimer) {
|
|
650
|
+
clearTimeout(this.batchTimer);
|
|
651
|
+
this.batchTimer = void 0;
|
|
652
|
+
}
|
|
653
|
+
const MAX_CLOSE_FLUSH_ATTEMPTS = 3;
|
|
654
|
+
for (let attempt = 0; attempt < MAX_CLOSE_FLUSH_ATTEMPTS && this.batch.length > 0; attempt += 1) await this.flush();
|
|
655
|
+
if (this.batch.length > 0) internalError(`Analytics transport ${this.name} closing with ${this.batch.length} unflushed entr${this.batch.length === 1 ? "y" : "ies"} after ${MAX_CLOSE_FLUSH_ATTEMPTS} attempts`);
|
|
603
656
|
await this.cleanup();
|
|
604
657
|
}
|
|
605
658
|
shouldSkipEntry(entry) {
|
|
@@ -1025,15 +1078,34 @@ var FileTransport = class {
|
|
|
1025
1078
|
await mkdir(dir, { recursive: true });
|
|
1026
1079
|
} catch {}
|
|
1027
1080
|
}
|
|
1028
|
-
|
|
1081
|
+
/**
|
|
1082
|
+
* Gzip the rotated file to `<file>.gz` and remove the original. Streams the
|
|
1083
|
+
* data so large log files don't have to be buffered in memory. Best-effort:
|
|
1084
|
+
* any failure is logged and leaves the original file intact rather than
|
|
1085
|
+
* throwing out of the rotation path.
|
|
1086
|
+
*/
|
|
1087
|
+
async compressFile(filePath) {
|
|
1088
|
+
const gzPath = `${filePath}.gz`;
|
|
1089
|
+
try {
|
|
1090
|
+
await pipeline(fs.createReadStream(filePath), createGzip(), fs.createWriteStream(gzPath));
|
|
1091
|
+
await unlink(filePath);
|
|
1092
|
+
} catch (error) {
|
|
1093
|
+
internalError("Failed to compress rotated log file", error);
|
|
1094
|
+
try {
|
|
1095
|
+
await unlink(gzPath);
|
|
1096
|
+
} catch {}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1029
1099
|
async cleanupOldFiles() {
|
|
1030
1100
|
var _this$config$rotation4;
|
|
1031
1101
|
if (!((_this$config$rotation4 = this.config.rotation) === null || _this$config$rotation4 === void 0 ? void 0 : _this$config$rotation4.maxFiles)) return;
|
|
1032
1102
|
try {
|
|
1033
1103
|
const dir = this.resolveDir();
|
|
1034
1104
|
const files = await readdir(dir);
|
|
1035
|
-
const
|
|
1036
|
-
const
|
|
1105
|
+
const ext = path.extname(this.config.filename);
|
|
1106
|
+
const base = path.basename(this.config.filename, ext);
|
|
1107
|
+
const isOwnRotatedFile = (file) => file.startsWith(`${base}-`) && (file.endsWith(ext) || file.endsWith(`${ext}.gz`));
|
|
1108
|
+
const logFiles = files.filter(isOwnRotatedFile).map(async (file) => {
|
|
1037
1109
|
const filePath = path.join(dir, file);
|
|
1038
1110
|
return {
|
|
1039
1111
|
path: filePath,
|
|
@@ -1834,7 +1906,7 @@ var TransportManager = class extends EventEmitter {
|
|
|
1834
1906
|
const writeTime = Date.now() - startTime;
|
|
1835
1907
|
metrics.logsWritten++;
|
|
1836
1908
|
metrics.lastWrite = new Date(startTime);
|
|
1837
|
-
metrics.averageWriteTime
|
|
1909
|
+
metrics.averageWriteTime += (writeTime - metrics.averageWriteTime) / metrics.logsWritten;
|
|
1838
1910
|
this.emit("log", entry);
|
|
1839
1911
|
} catch (error) {
|
|
1840
1912
|
metrics.errors++;
|
|
@@ -2062,4 +2134,4 @@ var TransportManager = class extends EventEmitter {
|
|
|
2062
2134
|
|
|
2063
2135
|
//#endregion
|
|
2064
2136
|
export { FileTransport as a, DatabaseTransport as c, internalError as d, internalLog as f, GoogleAnalyticsTransport as i, ConsoleTransport as l, __require as m, SegmentTransport as n, DataDogTransport as o, internalWarn as p, MixpanelTransport as r, AnalyticsTransport as s, TransportManager as t, safeToString as u };
|
|
2065
|
-
//# sourceMappingURL=transport.manager-
|
|
2137
|
+
//# sourceMappingURL=transport.manager-Cij_sA-b.mjs.map
|