logixia 1.12.6 → 1.13.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/README.md +19 -4
- package/dist/{async-context-CwBNMm2E.mjs → async-context-BzJrbfQs.mjs} +8 -4
- package/dist/async-context-BzJrbfQs.mjs.map +1 -0
- package/dist/{async-context-CSHWoHMB.js → async-context-DyQQYq3I.js} +8 -4
- package/dist/async-context-DyQQYq3I.js.map +1 -0
- package/dist/{azure-monitor.transport-CG7ClkYj.d.ts → azure-monitor.transport-BDFO4F-i.d.ts} +2 -2
- package/dist/{azure-monitor.transport-CG7ClkYj.d.ts.map → azure-monitor.transport-BDFO4F-i.d.ts.map} +1 -1
- package/dist/{azure-monitor.transport-Cm74kXZS.d.mts → azure-monitor.transport-D5wQEH04.d.mts} +2 -2
- package/dist/{azure-monitor.transport-Cm74kXZS.d.mts.map → azure-monitor.transport-D5wQEH04.d.mts.map} +1 -1
- package/dist/azure.d.mts +2 -2
- package/dist/azure.d.ts +2 -2
- package/dist/cli/index.js +98 -52
- package/dist/cloudwatch.d.mts +2 -2
- package/dist/cloudwatch.d.ts +2 -2
- package/dist/cloudwatch.js +2 -1
- package/dist/cloudwatch.mjs +2 -1
- package/dist/{cloudwatch.transport-CGHY4buE.d.mts → cloudwatch.transport-B00st6Xv.d.ts} +9 -2
- package/dist/cloudwatch.transport-B00st6Xv.d.ts.map +1 -0
- package/dist/{cloudwatch.transport-pNBNWJLt.js → cloudwatch.transport-BO1ahxw-.js} +26 -19
- package/dist/cloudwatch.transport-BO1ahxw-.js.map +1 -0
- package/dist/{cloudwatch.transport-DK_8cKd3.d.ts → cloudwatch.transport-Blc7Gtxt.d.mts} +9 -2
- package/dist/cloudwatch.transport-Blc7Gtxt.d.mts.map +1 -0
- package/dist/{cloudwatch.transport-yBwm4OeO.mjs → cloudwatch.transport-DZ6ies7g.mjs} +26 -19
- package/dist/cloudwatch.transport-DZ6ies7g.mjs.map +1 -0
- package/dist/{coerce.utils-BN980Y9V.js → coerce.utils-B-LilukN.js} +1 -1
- package/dist/{coerce.utils-BN980Y9V.js.map → coerce.utils-B-LilukN.js.map} +1 -1
- package/dist/{coerce.utils-Dxv4_ikC.mjs → coerce.utils-Cu6IUTgX.mjs} +1 -1
- package/dist/{coerce.utils-Dxv4_ikC.mjs.map → coerce.utils-Cu6IUTgX.mjs.map} +1 -1
- package/dist/correlation.d.mts +31 -6
- package/dist/correlation.d.mts.map +1 -1
- package/dist/correlation.d.ts +31 -6
- package/dist/correlation.d.ts.map +1 -1
- package/dist/correlation.js +45 -20
- package/dist/correlation.js.map +1 -1
- package/dist/correlation.mjs +45 -20
- package/dist/correlation.mjs.map +1 -1
- package/dist/entry-fields-BJkuPnIg.mjs +30 -0
- package/dist/entry-fields-BJkuPnIg.mjs.map +1 -0
- package/dist/entry-fields-BvOLFlJ4.js +36 -0
- package/dist/entry-fields-BvOLFlJ4.js.map +1 -0
- package/dist/gcp.d.mts +2 -2
- package/dist/gcp.d.ts +2 -2
- package/dist/gcp.js +2 -1
- package/dist/gcp.mjs +2 -1
- package/dist/{gcp.transport-SHdtc1n0.js → gcp.transport-CHV8MGgz.js} +5 -5
- package/dist/gcp.transport-CHV8MGgz.js.map +1 -0
- package/dist/{gcp.transport-BJuNRFe_.mjs → gcp.transport-DBX5TPIy.mjs} +5 -5
- package/dist/gcp.transport-DBX5TPIy.mjs.map +1 -0
- package/dist/{gcp.transport-BOhkVKlI.d.ts → gcp.transport-m4fVw0b1.d.ts} +2 -2
- package/dist/gcp.transport-m4fVw0b1.d.ts.map +1 -0
- package/dist/{gcp.transport-Bi6CUqZR.d.mts → gcp.transport-zzNyIoih.d.mts} +2 -2
- package/dist/gcp.transport-zzNyIoih.d.mts.map +1 -0
- package/dist/{index-BPKwwERo.d.mts → index-BPwEisy4.d.mts} +2 -2
- package/dist/{index-BPKwwERo.d.mts.map → index-BPwEisy4.d.mts.map} +1 -1
- package/dist/{index-C1X-TE5I.d.ts → index-nZEeCr3X.d.ts} +2 -2
- package/dist/{index-C1X-TE5I.d.ts.map → index-nZEeCr3X.d.ts.map} +1 -1
- package/dist/index.d.mts +63 -98
- package/dist/index.d.mts.map +1 -1
- package/dist/index.d.ts +63 -98
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +167 -443
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +98 -377
- package/dist/index.mjs.map +1 -1
- package/dist/middleware.d.mts +11 -4
- package/dist/middleware.d.mts.map +1 -1
- package/dist/middleware.d.ts +11 -4
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +148 -24
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +148 -24
- package/dist/middleware.mjs.map +1 -1
- package/dist/nest.d.mts +4 -4
- package/dist/nest.d.ts +4 -4
- package/dist/nest.js +20 -11
- package/dist/nest.mjs +7 -5
- package/dist/{logitron-logger.module-BsDZR5BH.js → nestjs-extras-DnJ6vrIC.js} +562 -444
- package/dist/nestjs-extras-DnJ6vrIC.js.map +1 -0
- package/dist/{logitron-logger.module-Bs3XYZgF.mjs → nestjs-extras-ImbuDhs1.mjs} +505 -349
- package/dist/nestjs-extras-ImbuDhs1.mjs.map +1 -0
- package/dist/{logitron-logger.module-zDKVd_o0.d.mts → nestjs-extras-OkC796py.d.mts} +113 -6
- package/dist/nestjs-extras-OkC796py.d.mts.map +1 -0
- package/dist/{logitron-logger.module-CxT1F6Cm.d.ts → nestjs-extras-mKrHE9S6.d.ts} +113 -6
- package/dist/nestjs-extras-mKrHE9S6.d.ts.map +1 -0
- package/dist/{search-njTI2hdo.js → search-B0MH1SJJ.js} +23 -10
- package/dist/search-B0MH1SJJ.js.map +1 -0
- package/dist/{search-DujhR94O.d.ts → search-BfBzDIT9.d.mts} +2 -3
- package/dist/search-BfBzDIT9.d.mts.map +1 -0
- package/dist/{search-CQOo-Iq6.d.mts → search-CHUZPl0h.d.ts} +2 -3
- package/dist/search-CHUZPl0h.d.ts.map +1 -0
- package/dist/{search-CFQRISUv.mjs → search-DjXSn6v5.mjs} +23 -10
- package/dist/search-DjXSn6v5.mjs.map +1 -0
- package/dist/search.d.mts +3 -3
- package/dist/search.d.ts +3 -3
- package/dist/search.js +2 -2
- package/dist/search.mjs +2 -2
- package/dist/testing.d.mts +2 -2
- package/dist/testing.d.ts +2 -2
- package/dist/trace.utils-CvXgaiQT.mjs +278 -0
- package/dist/trace.utils-CvXgaiQT.mjs.map +1 -0
- package/dist/trace.utils-DpBOLDtq.js +358 -0
- package/dist/trace.utils-DpBOLDtq.js.map +1 -0
- package/dist/{transport.manager-D6KL3t9V.mjs → transport.manager-CpdVHEGP.mjs} +365 -86
- package/dist/transport.manager-CpdVHEGP.mjs.map +1 -0
- package/dist/{transport.manager-BivyUTtU.js → transport.manager-Crau3Rle.js} +370 -85
- package/dist/transport.manager-Crau3Rle.js.map +1 -0
- package/dist/{transport.types-B5vcyv2k.d.mts → transport.types-CtNr3D7S.d.mts} +19 -2
- package/dist/transport.types-CtNr3D7S.d.mts.map +1 -0
- package/dist/{transport.types-BuY84TwO.d.ts → transport.types-DqVLZTyf.d.ts} +19 -2
- package/dist/transport.types-DqVLZTyf.d.ts.map +1 -0
- package/dist/transports.d.mts +38 -13
- package/dist/transports.d.mts.map +1 -1
- package/dist/transports.d.ts +38 -13
- package/dist/transports.d.ts.map +1 -1
- package/dist/transports.js +6 -5
- package/dist/transports.mjs +6 -5
- package/dist/worker-entry.js +307 -55
- package/dist/worker.d.mts +2 -2
- package/dist/worker.d.ts +2 -2
- package/dist/worker.js +1 -1
- package/dist/worker.mjs +1 -1
- package/dist/{worker.transport-BP8Q28Z2.d.mts → worker.transport-Bgv9heDI.d.mts} +2 -2
- package/dist/{worker.transport-BP8Q28Z2.d.mts.map → worker.transport-Bgv9heDI.d.mts.map} +1 -1
- package/dist/{worker.transport-mKXgNK0L.d.ts → worker.transport-Bj-i0P9V.d.ts} +2 -2
- package/dist/{worker.transport-mKXgNK0L.d.ts.map → worker.transport-Bj-i0P9V.d.ts.map} +1 -1
- package/dist/{worker.transport-CfH6z37Z.js → worker.transport-JP8YHBuU.js} +1 -1
- package/dist/{worker.transport-CfH6z37Z.js.map → worker.transport-JP8YHBuU.js.map} +1 -1
- package/dist/{worker.transport-BhMyvqQ2.mjs → worker.transport-otwhJ_Et.mjs} +1 -1
- package/dist/{worker.transport-BhMyvqQ2.mjs.map → worker.transport-otwhJ_Et.mjs.map} +1 -1
- package/package.json +10 -6
- package/dist/.tsbuildinfo +0 -1
- package/dist/async-context-CSHWoHMB.js.map +0 -1
- package/dist/async-context-CwBNMm2E.mjs.map +0 -1
- package/dist/cloudwatch.transport-CGHY4buE.d.mts.map +0 -1
- package/dist/cloudwatch.transport-DK_8cKd3.d.ts.map +0 -1
- package/dist/cloudwatch.transport-pNBNWJLt.js.map +0 -1
- package/dist/cloudwatch.transport-yBwm4OeO.mjs.map +0 -1
- package/dist/gcp.transport-BJuNRFe_.mjs.map +0 -1
- package/dist/gcp.transport-BOhkVKlI.d.ts.map +0 -1
- package/dist/gcp.transport-Bi6CUqZR.d.mts.map +0 -1
- package/dist/gcp.transport-SHdtc1n0.js.map +0 -1
- package/dist/logitron-logger.module-Bs3XYZgF.mjs.map +0 -1
- package/dist/logitron-logger.module-BsDZR5BH.js.map +0 -1
- package/dist/logitron-logger.module-CxT1F6Cm.d.ts.map +0 -1
- package/dist/logitron-logger.module-zDKVd_o0.d.mts.map +0 -1
- package/dist/search-CFQRISUv.mjs.map +0 -1
- package/dist/search-CQOo-Iq6.d.mts.map +0 -1
- package/dist/search-DujhR94O.d.ts.map +0 -1
- package/dist/search-njTI2hdo.js.map +0 -1
- package/dist/transport.manager-BivyUTtU.js.map +0 -1
- package/dist/transport.manager-D6KL3t9V.mjs.map +0 -1
- package/dist/transport.types-B5vcyv2k.d.mts.map +0 -1
- package/dist/transport.types-BuY84TwO.d.ts.map +0 -1
- package/scripts/postinstall.js +0 -61
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { t as __require } from "./chunk-DLSkYcPk.mjs";
|
|
2
2
|
import { n as internalLog, r as internalWarn, t as internalError } from "./internal-log-Cm8SOWSV.mjs";
|
|
3
3
|
import { i as stringifyForLog } from "./safe-stringify-DJ66tW5I.mjs";
|
|
4
|
-
import { t as
|
|
4
|
+
import { t as mergeCoreFields } from "./entry-fields-BJkuPnIg.mjs";
|
|
5
|
+
import { t as safeToString } from "./coerce.utils-Cu6IUTgX.mjs";
|
|
5
6
|
import * as fs from "node:fs";
|
|
6
7
|
import * as path$1 from "node:path";
|
|
7
8
|
import { EventEmitter } from "node:events";
|
|
@@ -9,6 +10,24 @@ import { pipeline } from "node:stream/promises";
|
|
|
9
10
|
import { promisify } from "node:util";
|
|
10
11
|
import { createGzip } from "node:zlib";
|
|
11
12
|
|
|
13
|
+
//#region src/utils/sanitize.utils.ts
|
|
14
|
+
/**
|
|
15
|
+
* Control-character stripping for text-mode log output.
|
|
16
|
+
*
|
|
17
|
+
* Line breaks become the visible escapes `\\n` / `\\r`; other C0 characters
|
|
18
|
+
* (except tab), DEL and C1 characters are removed, so user-supplied text cannot
|
|
19
|
+
* inject ANSI escapes, overwrite lines, or forge extra log entries.
|
|
20
|
+
*/
|
|
21
|
+
const CONTROL_CHARS_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]/g;
|
|
22
|
+
const VISIBLE_ESCAPES = {
|
|
23
|
+
"\n": "\\n",
|
|
24
|
+
"\r": "\\r"
|
|
25
|
+
};
|
|
26
|
+
function stripControlChars(value) {
|
|
27
|
+
return value.replace(CONTROL_CHARS_RE, (ch) => VISIBLE_ESCAPES[ch] ?? "");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
//#endregion
|
|
12
31
|
//#region src/transports/console.transport.ts
|
|
13
32
|
/**
|
|
14
33
|
* Writes log entries to stdout (info/debug/verbose) and stderr (error/warn).
|
|
@@ -39,9 +58,8 @@ var ConsoleTransport = class ConsoleTransport {
|
|
|
39
58
|
["brightwhite", "\x1B[97m"],
|
|
40
59
|
["reset", "\x1B[0m"]
|
|
41
60
|
]);
|
|
42
|
-
static #_2 = this.CONTROL_CHARS_RE = /[\x00-\x08\x0B-\x1F\x7F-\x9F]/g;
|
|
43
61
|
static sanitize(value) {
|
|
44
|
-
return safeToString(value)
|
|
62
|
+
return stripControlChars(safeToString(value));
|
|
45
63
|
}
|
|
46
64
|
constructor(config = {}) {
|
|
47
65
|
this.config = config;
|
|
@@ -54,16 +72,15 @@ var ConsoleTransport = class ConsoleTransport {
|
|
|
54
72
|
(lvl === "error" || lvl === "warn" ? process.stderr : process.stdout).write(formatted);
|
|
55
73
|
}
|
|
56
74
|
formatEntry(entry) {
|
|
57
|
-
if (this.config.format === "json") return stringifyForLog({
|
|
75
|
+
if (this.config.format === "json") return stringifyForLog(mergeCoreFields({
|
|
58
76
|
timestamp: this.config.timestamp !== false ? entry.timestamp.toISOString() : void 0,
|
|
59
77
|
level: entry.level,
|
|
60
78
|
message: entry.message,
|
|
61
|
-
...entry.data || {},
|
|
62
79
|
context: entry.context,
|
|
63
80
|
traceId: entry.traceId,
|
|
64
81
|
appName: entry.appName,
|
|
65
82
|
environment: entry.environment
|
|
66
|
-
});
|
|
83
|
+
}, entry.data));
|
|
67
84
|
const parts = [];
|
|
68
85
|
if (this.config.timestamp !== false) {
|
|
69
86
|
const timestamp = entry.timestamp.toISOString();
|
|
@@ -111,6 +128,47 @@ var ConsoleTransport = class ConsoleTransport {
|
|
|
111
128
|
}
|
|
112
129
|
};
|
|
113
130
|
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/transports/buffer-cap.ts
|
|
133
|
+
const DEFAULT_BUFFER_CAP = 1e4;
|
|
134
|
+
const DROP_WARN_INTERVAL_MS$1 = 5e3;
|
|
135
|
+
/**
|
|
136
|
+
* Keeps an in-memory retry buffer bounded. Past `max` the oldest items are
|
|
137
|
+
* dropped, counted, and reported through internalWarn at most every few seconds.
|
|
138
|
+
*
|
|
139
|
+
* `requested` must be an integer of at least 1, otherwise the default is used.
|
|
140
|
+
* A cap below `batchSize` is raised to `batchSize` so one batch always fits.
|
|
141
|
+
*/
|
|
142
|
+
var BufferCap = class {
|
|
143
|
+
constructor(name, requested, batchSize, fallback = DEFAULT_BUFFER_CAP) {
|
|
144
|
+
this.name = name;
|
|
145
|
+
this.dropped = 0;
|
|
146
|
+
this.lastWarning = 0;
|
|
147
|
+
let max = fallback;
|
|
148
|
+
if (requested !== void 0) if (Number.isInteger(requested) && requested >= 1) max = requested;
|
|
149
|
+
else internalWarn(`${name}: maxBufferSize ${String(requested)} is not a positive integer; using ${fallback}`);
|
|
150
|
+
this.max = Math.max(max, batchSize);
|
|
151
|
+
}
|
|
152
|
+
/** Drops the oldest items beyond the cap, in place. */
|
|
153
|
+
enforce(items) {
|
|
154
|
+
const excess = items.length - this.max;
|
|
155
|
+
if (excess <= 0) return;
|
|
156
|
+
items.splice(0, excess);
|
|
157
|
+
this.note(excess);
|
|
158
|
+
}
|
|
159
|
+
note(count) {
|
|
160
|
+
this.dropped += count;
|
|
161
|
+
this.report(DROP_WARN_INTERVAL_MS$1);
|
|
162
|
+
}
|
|
163
|
+
report(minGapMs) {
|
|
164
|
+
const now = Date.now();
|
|
165
|
+
if (this.dropped === 0 || now - this.lastWarning < minGapMs) return;
|
|
166
|
+
internalWarn(`${this.name}: buffer full (${this.max}), dropped ${this.dropped} oldest entr${this.dropped === 1 ? "y" : "ies"}`);
|
|
167
|
+
this.dropped = 0;
|
|
168
|
+
this.lastWarning = now;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
114
172
|
//#endregion
|
|
115
173
|
//#region src/transports/database.transport.ts
|
|
116
174
|
/**
|
|
@@ -121,6 +179,80 @@ const POSTGRES_MAX_PARAMS = 65535;
|
|
|
121
179
|
const POSTGRES_COLUMNS = 8;
|
|
122
180
|
const POSTGRES_ROWS_PER_INSERT = Math.floor(POSTGRES_MAX_PARAMS / POSTGRES_COLUMNS);
|
|
123
181
|
const MYSQL_ROWS_PER_INSERT = 5e3;
|
|
182
|
+
/** Postgres rejects NUL in TEXT and JSONB. */
|
|
183
|
+
function stripNul(value) {
|
|
184
|
+
return typeof value === "string" ? value.split("\0").join("") : value;
|
|
185
|
+
}
|
|
186
|
+
/** JSONB also rejects the \u0000 escape, which JSON.stringify writes for a NUL. */
|
|
187
|
+
function stripJsonNulEscape(value) {
|
|
188
|
+
if (typeof value !== "string") return value;
|
|
189
|
+
return value.replace(/(?<!\\)((?:\\\\)*)\\u0000/g, "$1");
|
|
190
|
+
}
|
|
191
|
+
const PG_DATA_CLASSES = [
|
|
192
|
+
"22",
|
|
193
|
+
"23",
|
|
194
|
+
"54"
|
|
195
|
+
];
|
|
196
|
+
const MYSQL_DATA_CODES = new Set([
|
|
197
|
+
"ER_DATA_TOO_LONG",
|
|
198
|
+
"ER_TRUNCATED_WRONG_VALUE",
|
|
199
|
+
"ER_TRUNCATED_WRONG_VALUE_FOR_FIELD",
|
|
200
|
+
"ER_BAD_NULL_ERROR",
|
|
201
|
+
"ER_WARN_DATA_OUT_OF_RANGE",
|
|
202
|
+
"ER_DUP_ENTRY",
|
|
203
|
+
"ER_INVALID_JSON_TEXT",
|
|
204
|
+
"ER_INVALID_CHARACTER_STRING"
|
|
205
|
+
]);
|
|
206
|
+
const MYSQL_DATA_ERRNOS = new Set([
|
|
207
|
+
1048,
|
|
208
|
+
1062,
|
|
209
|
+
1264,
|
|
210
|
+
1292,
|
|
211
|
+
1366,
|
|
212
|
+
1406,
|
|
213
|
+
3140
|
|
214
|
+
]);
|
|
215
|
+
const SQLITE_DATA_CODES = new Set([
|
|
216
|
+
"SQLITE_CONSTRAINT",
|
|
217
|
+
"SQLITE_TOOBIG",
|
|
218
|
+
"SQLITE_MISMATCH"
|
|
219
|
+
]);
|
|
220
|
+
const MONGO_DATA_CODES = new Set([
|
|
221
|
+
2,
|
|
222
|
+
121,
|
|
223
|
+
10334,
|
|
224
|
+
11e3
|
|
225
|
+
]);
|
|
226
|
+
function isDataErrorLayer(type, e) {
|
|
227
|
+
const code = e.code;
|
|
228
|
+
switch (type) {
|
|
229
|
+
case "postgresql": return typeof code === "string" && PG_DATA_CLASSES.includes(code.slice(0, 2));
|
|
230
|
+
case "mysql": return typeof code === "string" && MYSQL_DATA_CODES.has(code) || typeof e.errno === "number" && MYSQL_DATA_ERRNOS.has(e.errno);
|
|
231
|
+
case "sqlite": return typeof code === "string" && (SQLITE_DATA_CODES.has(code) || code.startsWith("SQLITE_CONSTRAINT_"));
|
|
232
|
+
case "mongodb": return e.name === "BSONObjectTooLarge" || typeof code === "number" && MONGO_DATA_CODES.has(code);
|
|
233
|
+
default: return false;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* True when the database refused the data itself (bad value, constraint, size),
|
|
238
|
+
* which retrying cannot fix. Connection, timeout, auth and unknown errors are
|
|
239
|
+
* not data errors and must be retried, never dropped.
|
|
240
|
+
*/
|
|
241
|
+
function isDataError(type, error) {
|
|
242
|
+
let current = error;
|
|
243
|
+
for (let depth = 0; depth < 3 && current && typeof current === "object"; depth += 1) {
|
|
244
|
+
if (isDataErrorLayer(type, current)) return true;
|
|
245
|
+
current = current.cause;
|
|
246
|
+
}
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
/** A write that stored part of a batch: only `remaining` still needs to be written. */
|
|
250
|
+
var PartialWriteError = class extends Error {
|
|
251
|
+
constructor(message, remaining, cause) {
|
|
252
|
+
super(message, { cause });
|
|
253
|
+
this.remaining = remaining;
|
|
254
|
+
}
|
|
255
|
+
};
|
|
124
256
|
function chunk(items, size) {
|
|
125
257
|
const chunks = [];
|
|
126
258
|
for (let i = 0; i < items.length; i += size) chunks.push(items.slice(i, i + size));
|
|
@@ -149,6 +281,7 @@ var DatabaseTransport = class {
|
|
|
149
281
|
this.isConnected = false;
|
|
150
282
|
this.batchSize = config.batchSize || 100;
|
|
151
283
|
this.flushInterval = config.flushInterval || 5e3;
|
|
284
|
+
this.cap = new BufferCap("DatabaseTransport", config.maxBufferSize, this.batchSize);
|
|
152
285
|
if (config.filter) this.filter = config.filter;
|
|
153
286
|
if (config.table) validateSqlIdentifier(config.table, "table");
|
|
154
287
|
this.setupFlushTimer();
|
|
@@ -160,6 +293,7 @@ var DatabaseTransport = class {
|
|
|
160
293
|
}
|
|
161
294
|
addToBatch(entry) {
|
|
162
295
|
this.batch.push(entry);
|
|
296
|
+
this.cap.enforce(this.batch);
|
|
163
297
|
}
|
|
164
298
|
async flush() {
|
|
165
299
|
if (!this.flushPromise) this.flushPromise = this.drain().finally(() => {
|
|
@@ -168,37 +302,97 @@ var DatabaseTransport = class {
|
|
|
168
302
|
await this.flushPromise;
|
|
169
303
|
}
|
|
170
304
|
/**
|
|
171
|
-
* Drains the
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
305
|
+
* Drains the buffer to the database one batch at a time. A batch is detached
|
|
306
|
+
* SYNCHRONOUSLY before awaiting the write, so entries appended by concurrent
|
|
307
|
+
* write() calls land in a fresh array and are never written twice.
|
|
308
|
+
*
|
|
309
|
+
* A failure that is not a data error (connection, timeout, auth, unknown) puts
|
|
310
|
+
* the batch back at the front of the buffer, bounded by `maxBufferSize`, and
|
|
311
|
+
* stops the loop so a down database is not hammered. A data error means the
|
|
312
|
+
* database refused some entry itself, so that batch alone is split to find and
|
|
313
|
+
* drop the refused entries; see isolate().
|
|
177
314
|
*/
|
|
178
315
|
async drain() {
|
|
179
316
|
while (this.batch.length > 0) {
|
|
180
|
-
const
|
|
181
|
-
this.batch = [];
|
|
317
|
+
const entries = this.batch.splice(0, this.batchSize);
|
|
182
318
|
try {
|
|
183
|
-
|
|
184
|
-
case "mongodb":
|
|
185
|
-
await this.flushToMongoDB(entriesToFlush);
|
|
186
|
-
break;
|
|
187
|
-
case "postgresql":
|
|
188
|
-
await this.flushToPostgreSQL(entriesToFlush);
|
|
189
|
-
break;
|
|
190
|
-
case "mysql":
|
|
191
|
-
await this.flushToMySQL(entriesToFlush);
|
|
192
|
-
break;
|
|
193
|
-
case "sqlite":
|
|
194
|
-
await this.flushToSQLite(entriesToFlush);
|
|
195
|
-
break;
|
|
196
|
-
default: throw new Error(`Unsupported database type: ${this.config.type}`);
|
|
197
|
-
}
|
|
319
|
+
await this.writeEntries(entries);
|
|
198
320
|
} catch (error) {
|
|
199
321
|
internalError("Database flush error", error);
|
|
200
|
-
|
|
201
|
-
|
|
322
|
+
if (error instanceof PartialWriteError) {
|
|
323
|
+
this.requeue(error.remaining);
|
|
324
|
+
throw error.cause;
|
|
325
|
+
}
|
|
326
|
+
if (!isDataError(this.config.type, error)) {
|
|
327
|
+
this.requeue(entries);
|
|
328
|
+
throw error;
|
|
329
|
+
}
|
|
330
|
+
const state = {
|
|
331
|
+
budget: 2 * this.batchSize,
|
|
332
|
+
rejected: 0,
|
|
333
|
+
requeue: [],
|
|
334
|
+
stopped: false
|
|
335
|
+
};
|
|
336
|
+
await this.isolate(entries, state);
|
|
337
|
+
if (state.rejected > 0) internalWarn(`DatabaseTransport: dropped ${state.rejected} log entr${state.rejected === 1 ? "y" : "ies"} the database rejected`);
|
|
338
|
+
this.requeue(state.requeue);
|
|
339
|
+
if (state.stopped) throw state.error;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
requeue(entries) {
|
|
344
|
+
if (entries.length === 0) return;
|
|
345
|
+
this.batch = entries.concat(this.batch);
|
|
346
|
+
this.cap.enforce(this.batch);
|
|
347
|
+
}
|
|
348
|
+
async writeEntries(entries) {
|
|
349
|
+
switch (this.config.type) {
|
|
350
|
+
case "mongodb":
|
|
351
|
+
await this.flushToMongoDB(entries);
|
|
352
|
+
break;
|
|
353
|
+
case "postgresql":
|
|
354
|
+
await this.flushToPostgreSQL(entries);
|
|
355
|
+
break;
|
|
356
|
+
case "mysql":
|
|
357
|
+
await this.flushToMySQL(entries);
|
|
358
|
+
break;
|
|
359
|
+
case "sqlite":
|
|
360
|
+
await this.flushToSQLite(entries);
|
|
361
|
+
break;
|
|
362
|
+
default: throw new Error(`Unsupported database type: ${this.config.type}`);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* `entries` failed with a data error. Splits them in half until the refused
|
|
367
|
+
* entries are alone and drops those. A write that fails with anything but a
|
|
368
|
+
* data error, or running out of the per-flush write budget, stops the search:
|
|
369
|
+
* the entries not yet written go back to the buffer.
|
|
370
|
+
*/
|
|
371
|
+
async isolate(entries, state) {
|
|
372
|
+
if (entries.length === 1) {
|
|
373
|
+
state.rejected += 1;
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
const mid = Math.ceil(entries.length / 2);
|
|
377
|
+
for (const half of [entries.slice(0, mid), entries.slice(mid)]) {
|
|
378
|
+
if (state.stopped || state.budget <= 0) {
|
|
379
|
+
state.requeue.push(...half);
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
state.budget -= 1;
|
|
383
|
+
try {
|
|
384
|
+
await this.writeEntries(half);
|
|
385
|
+
} catch (error) {
|
|
386
|
+
if (error instanceof PartialWriteError) {
|
|
387
|
+
state.requeue.push(...error.remaining);
|
|
388
|
+
state.stopped = true;
|
|
389
|
+
state.error = error.cause;
|
|
390
|
+
} else if (isDataError(this.config.type, error)) await this.isolate(half, state);
|
|
391
|
+
else {
|
|
392
|
+
state.requeue.push(...half);
|
|
393
|
+
state.stopped = true;
|
|
394
|
+
state.error = error;
|
|
395
|
+
}
|
|
202
396
|
}
|
|
203
397
|
}
|
|
204
398
|
}
|
|
@@ -323,7 +517,26 @@ var DatabaseTransport = class {
|
|
|
323
517
|
appName: entry.appName,
|
|
324
518
|
environment: entry.environment
|
|
325
519
|
}));
|
|
326
|
-
|
|
520
|
+
try {
|
|
521
|
+
await collection.insertMany(documents, { ordered: false });
|
|
522
|
+
} catch (error) {
|
|
523
|
+
const raw = error.writeErrors;
|
|
524
|
+
let list = [];
|
|
525
|
+
if (Array.isArray(raw)) list = raw;
|
|
526
|
+
else if (raw) list = [raw];
|
|
527
|
+
const writeErrors = list;
|
|
528
|
+
if (writeErrors.length === 0) throw error;
|
|
529
|
+
const remaining = [];
|
|
530
|
+
let rejected = 0;
|
|
531
|
+
for (const writeError of writeErrors) {
|
|
532
|
+
const entry = typeof writeError.index === "number" ? entries[writeError.index] : void 0;
|
|
533
|
+
if (!entry) throw error;
|
|
534
|
+
if (isDataError("mongodb", writeError)) rejected += 1;
|
|
535
|
+
else remaining.push(entry);
|
|
536
|
+
}
|
|
537
|
+
if (rejected > 0) internalWarn(`DatabaseTransport: dropped ${rejected} log entr${rejected === 1 ? "y" : "ies"} the database rejected`);
|
|
538
|
+
if (remaining.length > 0) throw new PartialWriteError("MongoDB insert partially failed", remaining, error);
|
|
539
|
+
}
|
|
327
540
|
}
|
|
328
541
|
async flushToPostgreSQL(entries) {
|
|
329
542
|
const tableName = this.config.table || "logs";
|
|
@@ -336,7 +549,7 @@ var DatabaseTransport = class {
|
|
|
336
549
|
entry.traceId,
|
|
337
550
|
entry.appName,
|
|
338
551
|
entry.environment
|
|
339
|
-
]), POSTGRES_ROWS_PER_INSERT);
|
|
552
|
+
].map((value, column) => stripNul(column === 3 ? stripJsonNulEscape(value) : value))), POSTGRES_ROWS_PER_INSERT);
|
|
340
553
|
const insertChunk = async (rows) => {
|
|
341
554
|
const query = `
|
|
342
555
|
INSERT INTO ${tableName}
|
|
@@ -496,6 +709,7 @@ var DatabaseTransport = class {
|
|
|
496
709
|
internalError("Database flush during close failed; entries remain buffered", error);
|
|
497
710
|
}
|
|
498
711
|
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`);
|
|
712
|
+
this.cap.report(0);
|
|
499
713
|
if (this.connection) switch (this.config.type) {
|
|
500
714
|
case "mongodb":
|
|
501
715
|
await this.connection.close();
|
|
@@ -567,6 +781,7 @@ var AnalyticsTransport = class {
|
|
|
567
781
|
this.level = config.level;
|
|
568
782
|
this.batchSize = this.config.batchSize || 50;
|
|
569
783
|
this.flushInterval = this.config.flushInterval || 1e4;
|
|
784
|
+
this.cap = new BufferCap(name, config.maxBufferSize, this.batchSize);
|
|
570
785
|
}
|
|
571
786
|
async write(entry) {
|
|
572
787
|
if (!this.isReady) await this.ensureReady();
|
|
@@ -576,6 +791,7 @@ var AnalyticsTransport = class {
|
|
|
576
791
|
}
|
|
577
792
|
addToBatch(entry) {
|
|
578
793
|
this.batch.push(entry);
|
|
794
|
+
this.cap.enforce(this.batch);
|
|
579
795
|
if (this.batch.length >= (this.config.batchSize || 50)) this.flush().catch((err) => internalError(`${this.name} batch flush failed`, err));
|
|
580
796
|
else if (!this.batchTimer && this.config.flushInterval) {
|
|
581
797
|
var _this$batchTimer$unre, _this$batchTimer;
|
|
@@ -611,6 +827,7 @@ var AnalyticsTransport = class {
|
|
|
611
827
|
} catch (error) {
|
|
612
828
|
internalError(`Analytics transport ${this.name} flush failed`, error);
|
|
613
829
|
this.batch.unshift(...entriesToSend);
|
|
830
|
+
this.cap.enforce(this.batch);
|
|
614
831
|
return;
|
|
615
832
|
}
|
|
616
833
|
}
|
|
@@ -623,25 +840,36 @@ var AnalyticsTransport = class {
|
|
|
623
840
|
const MAX_CLOSE_FLUSH_ATTEMPTS = 3;
|
|
624
841
|
for (let attempt = 0; attempt < MAX_CLOSE_FLUSH_ATTEMPTS && this.batch.length > 0; attempt += 1) await this.flush();
|
|
625
842
|
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`);
|
|
843
|
+
this.cap.report(0);
|
|
626
844
|
await this.cleanup();
|
|
627
845
|
}
|
|
628
846
|
shouldSkipEntry(entry) {
|
|
629
847
|
return ["debug", "trace"].includes(entry.level.toLowerCase());
|
|
630
848
|
}
|
|
631
849
|
transformEntry(entry) {
|
|
632
|
-
const
|
|
850
|
+
const core = {
|
|
633
851
|
timestamp: entry.timestamp.toISOString(),
|
|
634
852
|
level: entry.level,
|
|
635
853
|
message: entry.message,
|
|
636
|
-
|
|
854
|
+
context: entry.context,
|
|
855
|
+
traceId: entry.traceId,
|
|
856
|
+
appName: entry.appName,
|
|
857
|
+
environment: entry.environment
|
|
637
858
|
};
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
859
|
+
const transformed = mergeCoreFields(core, entry.data, this.reservedKeys());
|
|
860
|
+
for (const key of [
|
|
861
|
+
"context",
|
|
862
|
+
"traceId",
|
|
863
|
+
"appName",
|
|
864
|
+
"environment"
|
|
865
|
+
]) if (!core[key]) delete transformed[key];
|
|
642
866
|
if (this.config.customProperties) Object.assign(transformed, this.config.customProperties);
|
|
643
867
|
return transformed;
|
|
644
868
|
}
|
|
869
|
+
/** Provider-specific field names a payload key must not replace. */
|
|
870
|
+
reservedKeys() {
|
|
871
|
+
return [];
|
|
872
|
+
}
|
|
645
873
|
/**
|
|
646
874
|
* Runs initialize() once. A bad config (say, a missing API key) fails every
|
|
647
875
|
* write with the same error instead of an unhandled rejection at startup.
|
|
@@ -726,8 +954,12 @@ var DataDogTransport = class extends AnalyticsTransport {
|
|
|
726
954
|
await this.sendLogBatch(entries);
|
|
727
955
|
}
|
|
728
956
|
transformToDataDogLog(entry) {
|
|
729
|
-
const transformed = this.transformEntry(entry);
|
|
730
957
|
return {
|
|
958
|
+
...this.transformEntry(entry),
|
|
959
|
+
"dd.trace_id": entry.traceId,
|
|
960
|
+
"dd.span_id": this.generateSpanId(),
|
|
961
|
+
host: this.getHostname(),
|
|
962
|
+
source: "nodejs",
|
|
731
963
|
timestamp: entry.timestamp.toISOString(),
|
|
732
964
|
level: this.mapLogLevel(entry.level),
|
|
733
965
|
message: entry.message,
|
|
@@ -737,14 +969,25 @@ var DataDogTransport = class extends AnalyticsTransport {
|
|
|
737
969
|
logger: {
|
|
738
970
|
name: "logixia",
|
|
739
971
|
thread_name: "main"
|
|
740
|
-
}
|
|
741
|
-
...transformed,
|
|
742
|
-
"dd.trace_id": entry.traceId,
|
|
743
|
-
"dd.span_id": this.generateSpanId(),
|
|
744
|
-
host: this.getHostname(),
|
|
745
|
-
source: "nodejs"
|
|
972
|
+
}
|
|
746
973
|
};
|
|
747
974
|
}
|
|
975
|
+
reservedKeys() {
|
|
976
|
+
return [
|
|
977
|
+
"status",
|
|
978
|
+
"ddtags",
|
|
979
|
+
"ddsource",
|
|
980
|
+
"hostname",
|
|
981
|
+
"service",
|
|
982
|
+
"version",
|
|
983
|
+
"env",
|
|
984
|
+
"logger",
|
|
985
|
+
"host",
|
|
986
|
+
"source",
|
|
987
|
+
"dd.trace_id",
|
|
988
|
+
"dd.span_id"
|
|
989
|
+
];
|
|
990
|
+
}
|
|
748
991
|
transformToDataDogMetric(entry) {
|
|
749
992
|
return {
|
|
750
993
|
metric: `logitron.logs.${entry.level}`,
|
|
@@ -884,6 +1127,12 @@ const unlink = promisify(fs.unlink);
|
|
|
884
1127
|
const readdir = promisify(fs.readdir);
|
|
885
1128
|
const stat = promisify(fs.stat);
|
|
886
1129
|
const DROP_WARN_INTERVAL_MS = 5e3;
|
|
1130
|
+
const DEFAULT_MAX_QUEUE = 1e4;
|
|
1131
|
+
const DEFAULT_FILE_MODE = 384;
|
|
1132
|
+
const DEFAULT_DIR_MODE = 448;
|
|
1133
|
+
function csvField(value) {
|
|
1134
|
+
return `"${stripControlChars(safeToString(value)).replace(/"/g, "\"\"")}"`;
|
|
1135
|
+
}
|
|
887
1136
|
const SIZE_UNITS = {
|
|
888
1137
|
"": 1,
|
|
889
1138
|
k: 1024,
|
|
@@ -919,6 +1168,10 @@ function formatDatePattern(date, pattern) {
|
|
|
919
1168
|
* rotated files are renamed beside it (`app-2026-10-22T09-30-00-000.log`).
|
|
920
1169
|
* With a `rotation` block every file, the live one included, is timestamped.
|
|
921
1170
|
*
|
|
1171
|
+
* Files are created with mode 0o600 and directories with 0o700; override with
|
|
1172
|
+
* `fileMode` and `dirMode`. At most `maxQueue` (default 10000) entries wait in
|
|
1173
|
+
* memory; the rest are dropped per `queuePolicy` and counted in a warning.
|
|
1174
|
+
*
|
|
922
1175
|
* @example
|
|
923
1176
|
* transports: { file: { filename: 'app.log', dirname: './logs', maxSize: '50MB' } }
|
|
924
1177
|
*/
|
|
@@ -953,8 +1206,10 @@ var FileTransport = class {
|
|
|
953
1206
|
this.maxBytes = parseSize(rawMaxSize);
|
|
954
1207
|
if (rawMaxSize !== void 0 && this.maxBytes === void 0) internalWarn(`FileTransport: maxSize ${JSON.stringify(rawMaxSize)} is not a valid size (try '50MB'); size rotation is off`);
|
|
955
1208
|
const maxQueue = config.maxQueue;
|
|
956
|
-
if (maxQueue !== void 0 && !(Number.isInteger(maxQueue) && maxQueue > 0)) internalWarn(`FileTransport: maxQueue ${String(maxQueue)} is not a positive integer;
|
|
957
|
-
|
|
1209
|
+
if (maxQueue !== void 0 && !(Number.isInteger(maxQueue) && maxQueue > 0)) internalWarn(`FileTransport: maxQueue ${String(maxQueue)} is not a positive integer; using ${DEFAULT_MAX_QUEUE}`);
|
|
1210
|
+
this.maxQueue = maxQueue !== void 0 && Number.isInteger(maxQueue) && maxQueue > 0 ? maxQueue : DEFAULT_MAX_QUEUE;
|
|
1211
|
+
this.fileMode = config.fileMode ?? DEFAULT_FILE_MODE;
|
|
1212
|
+
this.dirMode = config.dirMode ?? DEFAULT_DIR_MODE;
|
|
958
1213
|
this.queuePolicy = config.queuePolicy ?? "drop-oldest";
|
|
959
1214
|
this.maxFiles = (rotation === null || rotation === void 0 ? void 0 : rotation.maxFiles) ?? config.maxFiles;
|
|
960
1215
|
this.compress = (rotation === null || rotation === void 0 ? void 0 : rotation.compress) ?? config.zippedArchive ?? false;
|
|
@@ -964,7 +1219,10 @@ var FileTransport = class {
|
|
|
964
1219
|
this.ext = path$1.extname(config.filename);
|
|
965
1220
|
this.base = path$1.basename(config.filename, this.ext);
|
|
966
1221
|
try {
|
|
967
|
-
fs.mkdirSync(this.dir, {
|
|
1222
|
+
fs.mkdirSync(this.dir, {
|
|
1223
|
+
recursive: true,
|
|
1224
|
+
mode: this.dirMode
|
|
1225
|
+
});
|
|
968
1226
|
} catch (error) {
|
|
969
1227
|
internalError(`FileTransport could not create ${this.dir}`, error);
|
|
970
1228
|
}
|
|
@@ -1032,7 +1290,7 @@ var FileTransport = class {
|
|
|
1032
1290
|
this.enqueued += 1;
|
|
1033
1291
|
}
|
|
1034
1292
|
queueFull() {
|
|
1035
|
-
return this.
|
|
1293
|
+
return this.batch.length + this.inFlight >= this.maxQueue;
|
|
1036
1294
|
}
|
|
1037
1295
|
roomAvailable() {
|
|
1038
1296
|
const room = new Promise((resolve) => this.spaceWaiters.push(resolve));
|
|
@@ -1112,30 +1370,26 @@ var FileTransport = class {
|
|
|
1112
1370
|
}
|
|
1113
1371
|
formatEntry(entry) {
|
|
1114
1372
|
switch (this.config.format) {
|
|
1115
|
-
case "json": return stringifyForLog({
|
|
1373
|
+
case "json": return stringifyForLog(mergeCoreFields({
|
|
1116
1374
|
timestamp: entry.timestamp.toISOString(),
|
|
1117
1375
|
level: entry.level,
|
|
1118
|
-
message: entry.message
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
safeToString(entry.traceId),
|
|
1129
|
-
stringifyForLog(entry.data || {})
|
|
1130
|
-
].join(",");
|
|
1131
|
-
}
|
|
1376
|
+
message: entry.message
|
|
1377
|
+
}, entry.data));
|
|
1378
|
+
case "csv": return [
|
|
1379
|
+
entry.timestamp.toISOString(),
|
|
1380
|
+
csvField(entry.level),
|
|
1381
|
+
csvField(entry.message),
|
|
1382
|
+
csvField(entry.context),
|
|
1383
|
+
csvField(entry.traceId),
|
|
1384
|
+
csvField(stringifyForLog(entry.data || {}))
|
|
1385
|
+
].join(",");
|
|
1132
1386
|
case "text":
|
|
1133
|
-
default: return `${entry.timestamp.toISOString()} [${entry.level.toUpperCase()}] ${safeToString(entry.message)}${entry.data ? " " + stringifyForLog(entry.data) : ""}`;
|
|
1387
|
+
default: return `${entry.timestamp.toISOString()} [${stripControlChars(safeToString(entry.level)).toUpperCase()}] ${stripControlChars(safeToString(entry.message))}${entry.data ? " " + stringifyForLog(entry.data) : ""}`;
|
|
1134
1388
|
}
|
|
1135
1389
|
}
|
|
1136
1390
|
addToBatch(entry) {
|
|
1137
1391
|
this.enqueue(entry);
|
|
1138
|
-
const threshold = Math.min(this.config.batchSize || 100, this.maxQueue
|
|
1392
|
+
const threshold = Math.min(this.config.batchSize || 100, this.maxQueue);
|
|
1139
1393
|
if (this.batch.length >= threshold && !this.draining) {
|
|
1140
1394
|
if (this.batchTimer) {
|
|
1141
1395
|
clearTimeout(this.batchTimer);
|
|
@@ -1173,7 +1427,7 @@ var FileTransport = class {
|
|
|
1173
1427
|
if (chunk$1) await this.append(chunk$1, chunkBytes);
|
|
1174
1428
|
}
|
|
1175
1429
|
async append(content, bytes = Buffer.byteLength(content)) {
|
|
1176
|
-
await appendFile(this.currentFilePath, content);
|
|
1430
|
+
await appendFile(this.currentFilePath, content, { mode: this.fileMode });
|
|
1177
1431
|
this.bytesWritten += bytes;
|
|
1178
1432
|
}
|
|
1179
1433
|
timeToRotate() {
|
|
@@ -1267,7 +1521,7 @@ var FileTransport = class {
|
|
|
1267
1521
|
async compressFile(filePath) {
|
|
1268
1522
|
const gzPath = `${filePath}.gz`;
|
|
1269
1523
|
try {
|
|
1270
|
-
await pipeline(fs.createReadStream(filePath), createGzip(), fs.createWriteStream(gzPath));
|
|
1524
|
+
await pipeline(fs.createReadStream(filePath), createGzip(), fs.createWriteStream(gzPath, { mode: this.fileMode }));
|
|
1271
1525
|
await unlink(filePath);
|
|
1272
1526
|
} catch (error) {
|
|
1273
1527
|
internalError("Failed to compress rotated log file", error);
|
|
@@ -1351,12 +1605,27 @@ var GoogleAnalyticsTransport = class extends AnalyticsTransport {
|
|
|
1351
1605
|
await this.sendEvents(events);
|
|
1352
1606
|
}
|
|
1353
1607
|
async cleanup() {}
|
|
1608
|
+
reservedKeys() {
|
|
1609
|
+
return [
|
|
1610
|
+
"event_category",
|
|
1611
|
+
"event_label",
|
|
1612
|
+
"log_level",
|
|
1613
|
+
"log_message",
|
|
1614
|
+
"trace_id",
|
|
1615
|
+
"app_name",
|
|
1616
|
+
"custom_dimension_1",
|
|
1617
|
+
"custom_dimension_2",
|
|
1618
|
+
"custom_dimension_3"
|
|
1619
|
+
];
|
|
1620
|
+
}
|
|
1354
1621
|
transformToGAEvent(entry) {
|
|
1355
1622
|
const transformed = this.transformEntry(entry);
|
|
1623
|
+
const eventCategory = this.mapLogLevelToCategory(entry.level);
|
|
1356
1624
|
return {
|
|
1357
1625
|
name: "log_event",
|
|
1358
1626
|
params: {
|
|
1359
|
-
|
|
1627
|
+
...this.flattenData(transformed),
|
|
1628
|
+
event_category: eventCategory,
|
|
1360
1629
|
event_label: entry.message,
|
|
1361
1630
|
log_level: entry.level,
|
|
1362
1631
|
log_message: entry.message,
|
|
@@ -1365,7 +1634,6 @@ var GoogleAnalyticsTransport = class extends AnalyticsTransport {
|
|
|
1365
1634
|
...entry.traceId && { trace_id: entry.traceId },
|
|
1366
1635
|
...entry.appName && { app_name: entry.appName },
|
|
1367
1636
|
...entry.environment && { environment: entry.environment },
|
|
1368
|
-
...this.flattenData(transformed),
|
|
1369
1637
|
custom_dimension_1: entry.level,
|
|
1370
1638
|
custom_dimension_2: entry.context || "default",
|
|
1371
1639
|
custom_dimension_3: entry.environment || "production"
|
|
@@ -1561,12 +1829,21 @@ var MixpanelTransport = class extends AnalyticsTransport {
|
|
|
1561
1829
|
await this.trackEvents(events);
|
|
1562
1830
|
}
|
|
1563
1831
|
async cleanup() {}
|
|
1832
|
+
reservedKeys() {
|
|
1833
|
+
return [
|
|
1834
|
+
"token",
|
|
1835
|
+
"distinct_id",
|
|
1836
|
+
"time",
|
|
1837
|
+
"$insert_id"
|
|
1838
|
+
];
|
|
1839
|
+
}
|
|
1564
1840
|
transformToMixpanelEvent(entry) {
|
|
1565
1841
|
const transformed = this.transformEntry(entry);
|
|
1566
1842
|
return {
|
|
1567
1843
|
name: `log_${entry.level}`,
|
|
1568
1844
|
properties: {
|
|
1569
1845
|
...transformed,
|
|
1846
|
+
token: this.mixpanelConfig.token,
|
|
1570
1847
|
distinct_id: this.mixpanelConfig.distinct_id || "anonymous",
|
|
1571
1848
|
time: entry.timestamp.getTime(),
|
|
1572
1849
|
$insert_id: this.generateInsertId(entry),
|
|
@@ -1579,8 +1856,8 @@ var MixpanelTransport = class extends AnalyticsTransport {
|
|
|
1579
1856
|
const payload = {
|
|
1580
1857
|
event: event.name,
|
|
1581
1858
|
properties: {
|
|
1582
|
-
|
|
1583
|
-
|
|
1859
|
+
...event.properties,
|
|
1860
|
+
token: this.mixpanelConfig.token
|
|
1584
1861
|
}
|
|
1585
1862
|
};
|
|
1586
1863
|
await this.makeRequest("/track", [payload]);
|
|
@@ -1589,8 +1866,8 @@ var MixpanelTransport = class extends AnalyticsTransport {
|
|
|
1589
1866
|
const payload = events.map((event) => ({
|
|
1590
1867
|
event: event.name,
|
|
1591
1868
|
properties: {
|
|
1592
|
-
|
|
1593
|
-
|
|
1869
|
+
...event.properties,
|
|
1870
|
+
token: this.mixpanelConfig.token
|
|
1594
1871
|
}
|
|
1595
1872
|
}));
|
|
1596
1873
|
await this.makeRequest("/track", payload);
|
|
@@ -1648,11 +1925,11 @@ var MixpanelTransport = class extends AnalyticsTransport {
|
|
|
1648
1925
|
const payload = {
|
|
1649
1926
|
event: eventName,
|
|
1650
1927
|
properties: {
|
|
1928
|
+
...properties,
|
|
1929
|
+
...this.mixpanelConfig.enableSuperProperties ? this.mixpanelConfig.superProperties : {},
|
|
1651
1930
|
token: this.mixpanelConfig.token,
|
|
1652
1931
|
distinct_id: this.mixpanelConfig.distinct_id || "anonymous",
|
|
1653
|
-
time: Date.now()
|
|
1654
|
-
...properties,
|
|
1655
|
-
...this.mixpanelConfig.enableSuperProperties ? this.mixpanelConfig.superProperties : {}
|
|
1932
|
+
time: Date.now()
|
|
1656
1933
|
}
|
|
1657
1934
|
};
|
|
1658
1935
|
await this.makeRequest("/track", [payload]);
|
|
@@ -1712,6 +1989,9 @@ var SegmentTransport = class extends AnalyticsTransport {
|
|
|
1712
1989
|
await this.batchTrack(segmentEvents);
|
|
1713
1990
|
}
|
|
1714
1991
|
async cleanup() {}
|
|
1992
|
+
reservedKeys() {
|
|
1993
|
+
return ["logger"];
|
|
1994
|
+
}
|
|
1715
1995
|
transformToSegmentEvent(entry) {
|
|
1716
1996
|
const transformed = this.transformEntry(entry);
|
|
1717
1997
|
return {
|
|
@@ -1721,10 +2001,10 @@ var SegmentTransport = class extends AnalyticsTransport {
|
|
|
1721
2001
|
anonymousId: this.generateAnonymousId(),
|
|
1722
2002
|
timestamp: entry.timestamp.toISOString(),
|
|
1723
2003
|
properties: {
|
|
2004
|
+
...transformed,
|
|
1724
2005
|
level: entry.level,
|
|
1725
2006
|
message: entry.message,
|
|
1726
2007
|
logger: "logixia",
|
|
1727
|
-
...transformed,
|
|
1728
2008
|
...entry.context && { context: entry.context },
|
|
1729
2009
|
...entry.traceId && { traceId: entry.traceId },
|
|
1730
2010
|
...entry.appName && { appName: entry.appName },
|
|
@@ -1780,11 +2060,10 @@ var SegmentTransport = class extends AnalyticsTransport {
|
|
|
1780
2060
|
}
|
|
1781
2061
|
}
|
|
1782
2062
|
extractUserId(entry) {
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
}
|
|
2063
|
+
var _entry$data;
|
|
2064
|
+
const field = this.segmentConfig.userIdField ?? "userId";
|
|
2065
|
+
const id = (_entry$data = entry.data) === null || _entry$data === void 0 ? void 0 : _entry$data[field];
|
|
2066
|
+
return typeof id === "string" ? id : void 0;
|
|
1788
2067
|
}
|
|
1789
2068
|
generateAnonymousId() {
|
|
1790
2069
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
|
|
@@ -2285,5 +2564,5 @@ var TransportManager = class extends EventEmitter {
|
|
|
2285
2564
|
};
|
|
2286
2565
|
|
|
2287
2566
|
//#endregion
|
|
2288
|
-
export { FileTransport as a, DatabaseTransport as c, GoogleAnalyticsTransport as i, ConsoleTransport as l, SegmentTransport as n, DataDogTransport as o, MixpanelTransport as r, AnalyticsTransport as s, TransportManager as t };
|
|
2289
|
-
//# sourceMappingURL=transport.manager-
|
|
2567
|
+
export { FileTransport as a, DatabaseTransport as c, GoogleAnalyticsTransport as i, ConsoleTransport as l, SegmentTransport as n, DataDogTransport as o, MixpanelTransport as r, AnalyticsTransport as s, TransportManager as t, stripControlChars as u };
|
|
2568
|
+
//# sourceMappingURL=transport.manager-CpdVHEGP.mjs.map
|