logixia 2.0.10 → 2.1.0
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 +2 -1
- package/dist/{async-context-Dv0bmPC-.js → async-context-Dgl3ZLyb.js} +4 -4
- package/dist/{async-context-Dv0bmPC-.js.map → async-context-Dgl3ZLyb.js.map} +1 -1
- package/dist/{async-context-COuvmwsS.mjs → async-context-fBqC5lNc.mjs} +3 -3
- package/dist/{async-context-COuvmwsS.mjs.map → async-context-fBqC5lNc.mjs.map} +1 -1
- package/dist/{azure-monitor.transport-CbSHOnNX.d.mts → azure-monitor.transport-C5VjvREZ.d.mts} +2 -2
- package/dist/{azure-monitor.transport-CbSHOnNX.d.mts.map → azure-monitor.transport-C5VjvREZ.d.mts.map} +1 -1
- package/dist/{azure-monitor.transport-Bvf7Xegt.d.ts → azure-monitor.transport-CyHDjHS-.d.ts} +2 -2
- package/dist/{azure-monitor.transport-Bvf7Xegt.d.ts.map → azure-monitor.transport-CyHDjHS-.d.ts.map} +1 -1
- package/dist/{azure-monitor.transport-Coz5Gesu.mjs → azure-monitor.transport-DGiacfvT.mjs} +19 -8
- package/dist/{azure-monitor.transport-Coz5Gesu.mjs.map → azure-monitor.transport-DGiacfvT.mjs.map} +1 -1
- package/dist/{azure-monitor.transport-D6ryi8rA.js → azure-monitor.transport-DX3fuK2t.js} +19 -8
- package/dist/{azure-monitor.transport-D6ryi8rA.js.map → azure-monitor.transport-DX3fuK2t.js.map} +1 -1
- package/dist/azure.d.mts +1 -1
- package/dist/azure.d.ts +1 -1
- package/dist/azure.js +1 -1
- package/dist/azure.mjs +1 -1
- package/dist/{batch-buffer-CFzKnuNZ.js → batch-buffer-BLmVvJAZ.js} +11 -7
- package/dist/{batch-buffer-CFzKnuNZ.js.map → batch-buffer-BLmVvJAZ.js.map} +1 -1
- package/dist/{batch-buffer-CQUWDMYq.mjs → batch-buffer-CM-lK_Qy.mjs} +11 -7
- package/dist/{batch-buffer-CQUWDMYq.mjs.map → batch-buffer-CM-lK_Qy.mjs.map} +1 -1
- package/dist/browser.d.mts +2 -0
- package/dist/browser.d.mts.map +1 -1
- package/dist/browser.d.ts +2 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +42 -13
- package/dist/browser.js.map +1 -1
- package/dist/browser.mjs +42 -13
- package/dist/browser.mjs.map +1 -1
- package/dist/{builder-Bj3mDeBw.mjs → builder-CA_dokb4.mjs} +246 -101
- package/dist/builder-CA_dokb4.mjs.map +1 -0
- package/dist/{builder-BLIStsCK.js → builder-jMlVYaQa.js} +256 -111
- package/dist/builder-jMlVYaQa.js.map +1 -0
- package/dist/cli/index.js +21 -16
- package/dist/cloudwatch.d.mts +1 -1
- package/dist/cloudwatch.d.ts +1 -1
- package/dist/cloudwatch.js +1 -1
- package/dist/cloudwatch.mjs +1 -1
- package/dist/{cloudwatch.transport-Cr1aeTGj.mjs → cloudwatch.transport-Cr0fEpko.mjs} +24 -9
- package/dist/{cloudwatch.transport-Cr1aeTGj.mjs.map → cloudwatch.transport-Cr0fEpko.mjs.map} +1 -1
- package/dist/{cloudwatch.transport-CQyT6U91.d.ts → cloudwatch.transport-DdSjUWvu.d.ts} +2 -2
- package/dist/{cloudwatch.transport-CQyT6U91.d.ts.map → cloudwatch.transport-DdSjUWvu.d.ts.map} +1 -1
- package/dist/{cloudwatch.transport-D4G5xYfG.js → cloudwatch.transport-Lst1Bbmr.js} +24 -9
- package/dist/{cloudwatch.transport-D4G5xYfG.js.map → cloudwatch.transport-Lst1Bbmr.js.map} +1 -1
- package/dist/{cloudwatch.transport-CjVrI6S4.d.mts → cloudwatch.transport-_hS7Mcc5.d.mts} +2 -2
- package/dist/{cloudwatch.transport-CjVrI6S4.d.mts.map → cloudwatch.transport-_hS7Mcc5.d.mts.map} +1 -1
- package/dist/correlation.js +3 -3
- package/dist/correlation.mjs +3 -3
- package/dist/{coerce.utils-C1C5sIX0.js → csv.utils-CbVHY1pd.js} +24 -1
- package/dist/csv.utils-CbVHY1pd.js.map +1 -0
- package/dist/{coerce.utils-B_rEudCn.mjs → csv.utils-ZdxSod5g.mjs} +19 -2
- package/dist/csv.utils-ZdxSod5g.mjs.map +1 -0
- package/dist/{entry-fields-CVwoQplO.js → entry-fields-BSLkzw18.js} +3 -3
- package/dist/{entry-fields-CVwoQplO.js.map → entry-fields-BSLkzw18.js.map} +1 -1
- package/dist/{entry-fields-DNTKQxoU.mjs → entry-fields-J1OBi24o.mjs} +2 -2
- package/dist/{entry-fields-DNTKQxoU.mjs.map → entry-fields-J1OBi24o.mjs.map} +1 -1
- package/dist/gcp.d.mts +1 -1
- package/dist/gcp.d.ts +1 -1
- package/dist/gcp.js +1 -1
- package/dist/gcp.mjs +1 -1
- package/dist/{gcp.transport-CVuRpchl.js → gcp.transport-5-ZIjN8r.js} +18 -9
- package/dist/{gcp.transport-CVuRpchl.js.map → gcp.transport-5-ZIjN8r.js.map} +1 -1
- package/dist/{gcp.transport-D9SdLPwP.d.mts → gcp.transport-C8VJiEM7.d.mts} +2 -2
- package/dist/{gcp.transport-D9SdLPwP.d.mts.map → gcp.transport-C8VJiEM7.d.mts.map} +1 -1
- package/dist/{gcp.transport-BCIvdFV-.d.ts → gcp.transport-Ct0BtKFo.d.ts} +2 -2
- package/dist/{gcp.transport-BCIvdFV-.d.ts.map → gcp.transport-Ct0BtKFo.d.ts.map} +1 -1
- package/dist/{gcp.transport-LLK2bw2-.mjs → gcp.transport-Cw3Qke85.mjs} +18 -9
- package/dist/{gcp.transport-LLK2bw2-.mjs.map → gcp.transport-Cw3Qke85.mjs.map} +1 -1
- package/dist/{index-BAkPHp5D.d.mts → index-B3ajtXJd.d.mts} +2 -2
- package/dist/{index-BAkPHp5D.d.mts.map → index-B3ajtXJd.d.mts.map} +1 -1
- package/dist/{index-e7LowmAu.d.ts → index-oqD3WNxf.d.ts} +2 -2
- package/dist/{index-e7LowmAu.d.ts.map → index-oqD3WNxf.d.ts.map} +1 -1
- package/dist/index.d.mts +8 -7
- package/dist/index.d.mts.map +1 -1
- package/dist/index.d.ts +8 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -26
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +34 -17
- package/dist/index.mjs.map +1 -1
- package/dist/{logitron-logger-DVUdgmBY.d.ts → logitron-logger-Csn3e6Qu.d.ts} +2 -2
- package/dist/{logitron-logger-DVUdgmBY.d.ts.map → logitron-logger-Csn3e6Qu.d.ts.map} +1 -1
- package/dist/{logitron-logger-DoWmMjYB.d.mts → logitron-logger-fMOkXr8H.d.mts} +2 -2
- package/dist/{logitron-logger-DoWmMjYB.d.mts.map → logitron-logger-fMOkXr8H.d.mts.map} +1 -1
- package/dist/middleware.d.mts +1 -1
- package/dist/middleware.d.mts.map +1 -1
- package/dist/middleware.d.ts +1 -1
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +12 -7
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +11 -6
- package/dist/middleware.mjs.map +1 -1
- package/dist/nest.d.mts +51 -18
- package/dist/nest.d.mts.map +1 -1
- package/dist/nest.d.ts +51 -18
- package/dist/nest.d.ts.map +1 -1
- package/dist/nest.js +207 -65
- package/dist/nest.js.map +1 -1
- package/dist/nest.mjs +202 -60
- package/dist/nest.mjs.map +1 -1
- package/dist/{otel-ChnVYRLA.js → otel-8ypFGG19.js} +452 -120
- package/dist/otel-8ypFGG19.js.map +1 -0
- package/dist/{otel-DOuwGPCd.mjs → otel-b-s2QbY4.mjs} +450 -118
- package/dist/otel-b-s2QbY4.mjs.map +1 -0
- package/dist/own-property-BWkibepN.js +40 -0
- package/dist/own-property-BWkibepN.js.map +1 -0
- package/dist/own-property-CjFw9qwZ.mjs +29 -0
- package/dist/own-property-CjFw9qwZ.mjs.map +1 -0
- package/dist/{request-trace-ByujsUZk.js → request-trace-C7kXMjx5.js} +5 -6
- package/dist/{request-trace-ByujsUZk.js.map → request-trace-C7kXMjx5.js.map} +1 -1
- package/dist/{request-trace-BgNykH9M.mjs → request-trace-Dekcnenb.mjs} +5 -6
- package/dist/{request-trace-BgNykH9M.mjs.map → request-trace-Dekcnenb.mjs.map} +1 -1
- package/dist/{safe-stringify--7gbe95n.mjs → safe-stringify-B5p5ktFe.mjs} +2 -2
- package/dist/{safe-stringify--7gbe95n.mjs.map → safe-stringify-B5p5ktFe.mjs.map} +1 -1
- package/dist/{safe-stringify-CN7icp8S.js → safe-stringify-J3sh-7YM.js} +5 -5
- package/dist/{safe-stringify-CN7icp8S.js.map → safe-stringify-J3sh-7YM.js.map} +1 -1
- package/dist/{search-DPwTKPve.d.ts → search-B-hJe2N-.d.mts} +9 -8
- package/dist/{search-D-8HJADE.d.mts.map → search-B-hJe2N-.d.mts.map} +1 -1
- package/dist/{search-D-8HJADE.d.mts → search-BlKBLm5D.d.ts} +9 -8
- package/dist/{search-DPwTKPve.d.ts.map → search-BlKBLm5D.d.ts.map} +1 -1
- package/dist/{search-DAXKE-P9.mjs → search-CTR4XNHq.mjs} +91 -44
- package/dist/search-CTR4XNHq.mjs.map +1 -0
- package/dist/{search-CRjhHxe9.js → search-_qx4YzRP.js} +94 -47
- package/dist/search-_qx4YzRP.js.map +1 -0
- package/dist/search.d.mts +1 -1
- package/dist/search.d.ts +1 -1
- package/dist/search.js +1 -1
- package/dist/search.mjs +1 -1
- package/dist/{secret-config-BvFl2dC8.js → secret-config--cVTOWwp.js} +6 -5
- package/dist/{secret-config-BvFl2dC8.js.map → secret-config--cVTOWwp.js.map} +1 -1
- package/dist/{secret-config-ByGq7kJd.mjs → secret-config-GKmb15Me.mjs} +3 -2
- package/dist/{secret-config-ByGq7kJd.mjs.map → secret-config-GKmb15Me.mjs.map} +1 -1
- package/dist/{sensitive-names-o__1PUUR.mjs → sensitive-names-BiBM6R1X.mjs} +2 -28
- package/dist/sensitive-names-BiBM6R1X.mjs.map +1 -0
- package/dist/{sensitive-names-CHMowujD.js → sensitive-names-NiKIRhp5.js} +5 -37
- package/dist/sensitive-names-NiKIRhp5.js.map +1 -0
- package/dist/{slack.transport-BDyENuR0.d.mts → slack.transport-5OPL7H3u.d.mts} +76 -3
- package/dist/slack.transport-5OPL7H3u.d.mts.map +1 -0
- package/dist/{slack.transport-C6E0l4kw.d.ts → slack.transport-BFpBD_Ri.d.ts} +76 -3
- package/dist/slack.transport-BFpBD_Ri.d.ts.map +1 -0
- package/dist/{slack.transport-zLQ9MGxS.js → slack.transport-Cpx5fKga.js} +272 -21
- package/dist/slack.transport-Cpx5fKga.js.map +1 -0
- package/dist/{slack.transport-CSj1j0_X.mjs → slack.transport-Qwj9WkrJ.mjs} +267 -22
- package/dist/slack.transport-Qwj9WkrJ.mjs.map +1 -0
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/{transport.types-CzJq4IrF.d.ts → transport.types-B1ejJJP6.d.mts} +6 -1
- package/dist/transport.types-B1ejJJP6.d.mts.map +1 -0
- package/dist/{transport.types-CzJq4IrF.d.mts → transport.types-B1ejJJP6.d.ts} +6 -1
- package/dist/transport.types-B1ejJJP6.d.ts.map +1 -0
- package/dist/transports.d.mts +61 -11
- package/dist/transports.d.mts.map +1 -1
- package/dist/transports.d.ts +61 -11
- package/dist/transports.d.ts.map +1 -1
- package/dist/transports.js +7 -6
- package/dist/transports.mjs +7 -7
- package/dist/worker-entry.js +200 -52
- package/dist/worker.d.mts +1 -1
- package/dist/worker.d.ts +1 -1
- package/dist/worker.js +1 -1
- package/dist/worker.mjs +1 -1
- package/dist/{worker.transport-B9mCQSM1.d.ts → worker.transport-B7olL1Uh.d.ts} +12 -2
- package/dist/worker.transport-B7olL1Uh.d.ts.map +1 -0
- package/dist/{worker.transport-D78xhNhB.mjs → worker.transport-BHnWDXPH.mjs} +59 -13
- package/dist/worker.transport-BHnWDXPH.mjs.map +1 -0
- package/dist/{worker.transport-DQDv1nAJ.js → worker.transport-C7jNGhev.js} +59 -13
- package/dist/worker.transport-C7jNGhev.js.map +1 -0
- package/dist/{worker.transport-Bl8lFRck.d.mts → worker.transport-DnU0_9Bd.d.mts} +12 -2
- package/dist/worker.transport-DnU0_9Bd.d.mts.map +1 -0
- package/package.json +10 -3
- package/dist/builder-BLIStsCK.js.map +0 -1
- package/dist/builder-Bj3mDeBw.mjs.map +0 -1
- package/dist/coerce.utils-B_rEudCn.mjs.map +0 -1
- package/dist/coerce.utils-C1C5sIX0.js.map +0 -1
- package/dist/otel-ChnVYRLA.js.map +0 -1
- package/dist/otel-DOuwGPCd.mjs.map +0 -1
- package/dist/search-CRjhHxe9.js.map +0 -1
- package/dist/search-DAXKE-P9.mjs.map +0 -1
- package/dist/sensitive-names-CHMowujD.js.map +0 -1
- package/dist/sensitive-names-o__1PUUR.mjs.map +0 -1
- package/dist/slack.transport-BDyENuR0.d.mts.map +0 -1
- package/dist/slack.transport-C6E0l4kw.d.ts.map +0 -1
- package/dist/slack.transport-CSj1j0_X.mjs.map +0 -1
- package/dist/slack.transport-zLQ9MGxS.js.map +0 -1
- package/dist/transport.types-CzJq4IrF.d.mts.map +0 -1
- package/dist/transport.types-CzJq4IrF.d.ts.map +0 -1
- package/dist/worker.transport-B9mCQSM1.d.ts.map +0 -1
- package/dist/worker.transport-Bl8lFRck.d.mts.map +0 -1
- package/dist/worker.transport-D78xhNhB.mjs.map +0 -1
- package/dist/worker.transport-DQDv1nAJ.js.map +0 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
const require_secret_config = require("./secret-config
|
|
1
|
+
const require_secret_config = require("./secret-config--cVTOWwp.js");
|
|
2
2
|
const require_internal_log = require("./internal-log-DwqTjhpb.js");
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const require_entry_fields = require("./entry-fields-
|
|
3
|
+
const require_safe_stringify = require("./safe-stringify-J3sh-7YM.js");
|
|
4
|
+
const require_csv_utils = require("./csv.utils-CbVHY1pd.js");
|
|
5
|
+
const require_entry_fields = require("./entry-fields-BSLkzw18.js");
|
|
6
|
+
const require_batch_buffer = require("./batch-buffer-BLmVvJAZ.js");
|
|
6
7
|
let node_events = require("node:events");
|
|
7
8
|
let node_util = require("node:util");
|
|
8
9
|
let node_zlib = require("node:zlib");
|
|
@@ -37,12 +38,35 @@ function stripControlChars(value) {
|
|
|
37
38
|
* transports: { console: { format: 'json' } }
|
|
38
39
|
*/
|
|
39
40
|
var ConsoleTransport = class ConsoleTransport {
|
|
41
|
+
config;
|
|
42
|
+
name = "console";
|
|
43
|
+
level;
|
|
44
|
+
filter;
|
|
45
|
+
static COLORS = /* @__PURE__ */ new Map([
|
|
46
|
+
["black", "\x1B[30m"],
|
|
47
|
+
["red", "\x1B[31m"],
|
|
48
|
+
["green", "\x1B[32m"],
|
|
49
|
+
["yellow", "\x1B[33m"],
|
|
50
|
+
["blue", "\x1B[34m"],
|
|
51
|
+
["magenta", "\x1B[35m"],
|
|
52
|
+
["cyan", "\x1B[36m"],
|
|
53
|
+
["white", "\x1B[37m"],
|
|
54
|
+
["gray", "\x1B[90m"],
|
|
55
|
+
["grey", "\x1B[90m"],
|
|
56
|
+
["brightred", "\x1B[91m"],
|
|
57
|
+
["brightgreen", "\x1B[92m"],
|
|
58
|
+
["brightyellow", "\x1B[93m"],
|
|
59
|
+
["brightblue", "\x1B[94m"],
|
|
60
|
+
["brightmagenta", "\x1B[95m"],
|
|
61
|
+
["brightcyan", "\x1B[96m"],
|
|
62
|
+
["brightwhite", "\x1B[97m"],
|
|
63
|
+
["reset", "\x1B[0m"]
|
|
64
|
+
]);
|
|
40
65
|
static sanitize(value) {
|
|
41
|
-
return stripControlChars(
|
|
66
|
+
return stripControlChars(require_csv_utils.safeToString(value));
|
|
42
67
|
}
|
|
43
68
|
constructor(config = {}) {
|
|
44
69
|
this.config = config;
|
|
45
|
-
this.name = "console";
|
|
46
70
|
this.level = config.level;
|
|
47
71
|
if (config.filter) this.filter = config.filter;
|
|
48
72
|
}
|
|
@@ -106,26 +130,6 @@ var ConsoleTransport = class ConsoleTransport {
|
|
|
106
130
|
close() {
|
|
107
131
|
return Promise.resolve();
|
|
108
132
|
}
|
|
109
|
-
static #_ = () => this.COLORS = /* @__PURE__ */ new Map([
|
|
110
|
-
["black", "\x1B[30m"],
|
|
111
|
-
["red", "\x1B[31m"],
|
|
112
|
-
["green", "\x1B[32m"],
|
|
113
|
-
["yellow", "\x1B[33m"],
|
|
114
|
-
["blue", "\x1B[34m"],
|
|
115
|
-
["magenta", "\x1B[35m"],
|
|
116
|
-
["cyan", "\x1B[36m"],
|
|
117
|
-
["white", "\x1B[37m"],
|
|
118
|
-
["gray", "\x1B[90m"],
|
|
119
|
-
["grey", "\x1B[90m"],
|
|
120
|
-
["brightred", "\x1B[91m"],
|
|
121
|
-
["brightgreen", "\x1B[92m"],
|
|
122
|
-
["brightyellow", "\x1B[93m"],
|
|
123
|
-
["brightblue", "\x1B[94m"],
|
|
124
|
-
["brightmagenta", "\x1B[95m"],
|
|
125
|
-
["brightcyan", "\x1B[96m"],
|
|
126
|
-
["brightwhite", "\x1B[97m"],
|
|
127
|
-
["reset", "\x1B[0m"]
|
|
128
|
-
]);
|
|
129
133
|
};
|
|
130
134
|
// src/transports/buffer-cap.ts
|
|
131
135
|
const DEFAULT_BUFFER_CAP = 1e4;
|
|
@@ -138,10 +142,12 @@ const DROP_WARN_INTERVAL_MS$1 = 5e3;
|
|
|
138
142
|
* A cap below `batchSize` is raised to `batchSize` so one batch always fits.
|
|
139
143
|
*/
|
|
140
144
|
var BufferCap = class {
|
|
145
|
+
name;
|
|
146
|
+
max;
|
|
147
|
+
dropped = 0;
|
|
148
|
+
lastWarning = 0;
|
|
141
149
|
constructor(name, requested, batchSize, fallback = DEFAULT_BUFFER_CAP) {
|
|
142
150
|
this.name = name;
|
|
143
|
-
this.dropped = 0;
|
|
144
|
-
this.lastWarning = 0;
|
|
145
151
|
let max = fallback;
|
|
146
152
|
if (requested !== void 0) {
|
|
147
153
|
if (Number.isInteger(requested) && requested >= 1) max = requested;
|
|
@@ -245,7 +251,9 @@ function isDataError(type, error) {
|
|
|
245
251
|
return false;
|
|
246
252
|
}
|
|
247
253
|
/** A write that stored part of a batch: only `remaining` still needs to be written. */
|
|
254
|
+
var DatabaseUnavailableError = class extends Error {};
|
|
248
255
|
var PartialWriteError = class extends Error {
|
|
256
|
+
remaining;
|
|
249
257
|
constructor(message, remaining, cause) {
|
|
250
258
|
super(message, { cause });
|
|
251
259
|
this.remaining = remaining;
|
|
@@ -272,11 +280,30 @@ function validateSqlIdentifier(name, label = "table") {
|
|
|
272
280
|
* }
|
|
273
281
|
*/
|
|
274
282
|
var DatabaseTransport = class {
|
|
283
|
+
config;
|
|
284
|
+
name = "database";
|
|
285
|
+
batchSize;
|
|
286
|
+
flushInterval;
|
|
287
|
+
level;
|
|
288
|
+
filter;
|
|
289
|
+
batch = [];
|
|
290
|
+
flushTimer;
|
|
291
|
+
/**
|
|
292
|
+
* The in-flight drain promise, or undefined when idle. Concurrent flush()
|
|
293
|
+
* calls (the un-awaited threshold flush write() fires, plus the interval
|
|
294
|
+
* timer) all await this single promise instead of starting their own drain,
|
|
295
|
+
* so a batch is never snapshotted and written twice. Mirrors the FileTransport
|
|
296
|
+
* fix for the overlapping-batch-flush duplication bug.
|
|
297
|
+
*/
|
|
298
|
+
flushPromise;
|
|
299
|
+
connection;
|
|
300
|
+
isConnected = false;
|
|
301
|
+
connectionPromise;
|
|
302
|
+
connectFailures = 0;
|
|
303
|
+
nextConnectAt = 0;
|
|
304
|
+
cap;
|
|
275
305
|
constructor(config) {
|
|
276
306
|
this.config = config;
|
|
277
|
-
this.name = "database";
|
|
278
|
-
this.batch = [];
|
|
279
|
-
this.isConnected = false;
|
|
280
307
|
require_secret_config.protectSecrets(this, ["config", "connection"]);
|
|
281
308
|
this.batchSize = config.batchSize || 100;
|
|
282
309
|
this.flushInterval = config.flushInterval || 5e3;
|
|
@@ -295,9 +322,12 @@ var DatabaseTransport = class {
|
|
|
295
322
|
];
|
|
296
323
|
}
|
|
297
324
|
async write(entry) {
|
|
298
|
-
if (!this.isConnected) await this.connect();
|
|
299
325
|
this.addToBatch(entry);
|
|
300
|
-
if (this.batch.length >= this.batchSize)
|
|
326
|
+
if (this.batch.length >= this.batchSize) try {
|
|
327
|
+
await this.flush();
|
|
328
|
+
} catch (error) {
|
|
329
|
+
if (!(error instanceof DatabaseUnavailableError)) throw error;
|
|
330
|
+
}
|
|
301
331
|
}
|
|
302
332
|
addToBatch(entry) {
|
|
303
333
|
this.batch.push(entry);
|
|
@@ -322,6 +352,7 @@ var DatabaseTransport = class {
|
|
|
322
352
|
*/
|
|
323
353
|
async drain() {
|
|
324
354
|
while (this.batch.length > 0) {
|
|
355
|
+
await this.ensureConnected();
|
|
325
356
|
const entries = this.batch.splice(0, this.batchSize);
|
|
326
357
|
try {
|
|
327
358
|
await this.writeEntries(entries);
|
|
@@ -419,6 +450,38 @@ var DatabaseTransport = class {
|
|
|
419
450
|
return false;
|
|
420
451
|
}
|
|
421
452
|
}
|
|
453
|
+
async ensureConnected() {
|
|
454
|
+
if (this.isConnected) return;
|
|
455
|
+
const wait = this.nextConnectAt - Date.now();
|
|
456
|
+
if (wait > 0) throw new DatabaseUnavailableError(`Database unavailable; next connect attempt in ${wait}ms`);
|
|
457
|
+
try {
|
|
458
|
+
await this.connect();
|
|
459
|
+
this.connectFailures = 0;
|
|
460
|
+
} catch (error) {
|
|
461
|
+
this.connectFailures += 1;
|
|
462
|
+
this.nextConnectAt = Date.now() + Math.min(3e4, 1e3 * 2 ** (this.connectFailures - 1));
|
|
463
|
+
require_internal_log.internalError("Database connection error", error);
|
|
464
|
+
throw new DatabaseUnavailableError("Database unavailable", { cause: error });
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* The driver reported the connection gone (idle timeout, server restart,
|
|
469
|
+
* network drop). Forget it so the next flush reconnects; without an 'error'
|
|
470
|
+
* listener the driver's emitter would crash the process.
|
|
471
|
+
*/
|
|
472
|
+
onConnectionLost(connection, error) {
|
|
473
|
+
if (this.connection !== connection) return;
|
|
474
|
+
if (error) require_internal_log.internalError("Database connection lost", error);
|
|
475
|
+
this.isConnected = false;
|
|
476
|
+
this.connectionPromise = void 0;
|
|
477
|
+
this.connection = void 0;
|
|
478
|
+
}
|
|
479
|
+
watchConnection(connection) {
|
|
480
|
+
var _connection$on, _connection$on2;
|
|
481
|
+
const lost = (error) => this.onConnectionLost(connection, error);
|
|
482
|
+
(_connection$on = connection.on) === null || _connection$on === void 0 || _connection$on.call(connection, "error", lost);
|
|
483
|
+
(_connection$on2 = connection.on) === null || _connection$on2 === void 0 || _connection$on2.call(connection, "end", () => lost());
|
|
484
|
+
}
|
|
422
485
|
async connect() {
|
|
423
486
|
if (this.connectionPromise) return this.connectionPromise;
|
|
424
487
|
this.connectionPromise = this.establishConnection().catch((error) => {
|
|
@@ -455,6 +518,7 @@ var DatabaseTransport = class {
|
|
|
455
518
|
});
|
|
456
519
|
const connectionString = this.config.connectionString || `mongodb://${this.config.host}:${this.config.port}/${this.config.database}`;
|
|
457
520
|
this.connection = new MongoClient(connectionString);
|
|
521
|
+
this.watchConnection(this.connection);
|
|
458
522
|
await this.connection.connect();
|
|
459
523
|
await this.connection.db(this.config.database).admin().ping();
|
|
460
524
|
} catch (error) {
|
|
@@ -476,6 +540,7 @@ var DatabaseTransport = class {
|
|
|
476
540
|
if (this.config.password) config.password = this.config.password;
|
|
477
541
|
if (this.config.ssl) config.ssl = typeof this.config.ssl === "boolean" ? {} : this.config.ssl;
|
|
478
542
|
this.connection = new Client(config);
|
|
543
|
+
this.watchConnection(this.connection);
|
|
479
544
|
await this.connection.connect();
|
|
480
545
|
await this.createPostgreSQLTable();
|
|
481
546
|
} catch (error) {
|
|
@@ -496,6 +561,7 @@ var DatabaseTransport = class {
|
|
|
496
561
|
if (this.config.password) config.password = this.config.password;
|
|
497
562
|
if (this.config.ssl) config.ssl = typeof this.config.ssl === "boolean" ? {} : this.config.ssl;
|
|
498
563
|
this.connection = await mysql.createConnection(config);
|
|
564
|
+
this.watchConnection(this.connection);
|
|
499
565
|
await this.createMySQLTable();
|
|
500
566
|
} catch (error) {
|
|
501
567
|
throw new Error(`MySQL connection failed: ${error}`, { cause: error });
|
|
@@ -718,6 +784,7 @@ var DatabaseTransport = class {
|
|
|
718
784
|
this.flushTimer = void 0;
|
|
719
785
|
}
|
|
720
786
|
const MAX_CLOSE_FLUSH_ATTEMPTS = 3;
|
|
787
|
+
this.nextConnectAt = 0;
|
|
721
788
|
if (this.flushPromise) await this.flushPromise.catch(() => {});
|
|
722
789
|
for (let attempt = 0; attempt < MAX_CLOSE_FLUSH_ATTEMPTS && this.batch.length > 0; attempt += 1) try {
|
|
723
790
|
await this.flush();
|
|
@@ -726,17 +793,19 @@ var DatabaseTransport = class {
|
|
|
726
793
|
}
|
|
727
794
|
if (this.batch.length > 0) require_internal_log.internalError(`Database transport closing with ${this.batch.length} unflushed log entr${this.batch.length === 1 ? "y" : "ies"} after ${MAX_CLOSE_FLUSH_ATTEMPTS} attempts`);
|
|
728
795
|
this.cap.report(0);
|
|
729
|
-
|
|
796
|
+
const connection = this.connection;
|
|
797
|
+
this.connection = void 0;
|
|
798
|
+
if (connection) switch (this.config.type) {
|
|
730
799
|
case "mongodb":
|
|
731
|
-
await
|
|
800
|
+
await connection.close();
|
|
732
801
|
break;
|
|
733
802
|
case "postgresql":
|
|
734
|
-
await
|
|
803
|
+
await connection.end();
|
|
735
804
|
break;
|
|
736
805
|
case "mysql":
|
|
737
|
-
await
|
|
806
|
+
await connection.end();
|
|
738
807
|
break;
|
|
739
|
-
case "sqlite": await
|
|
808
|
+
case "sqlite": await connection.close();
|
|
740
809
|
}
|
|
741
810
|
this.isConnected = false;
|
|
742
811
|
}
|
|
@@ -783,6 +852,7 @@ var DatabaseTransport = class {
|
|
|
783
852
|
* requeues only `unsent`, so delivered entries are not sent twice.
|
|
784
853
|
*/
|
|
785
854
|
var PartialBatchError = class extends Error {
|
|
855
|
+
unsent;
|
|
786
856
|
constructor(message, unsent, options) {
|
|
787
857
|
super(message, options);
|
|
788
858
|
this.unsent = unsent;
|
|
@@ -790,9 +860,30 @@ var PartialBatchError = class extends Error {
|
|
|
790
860
|
}
|
|
791
861
|
};
|
|
792
862
|
var AnalyticsTransport = class {
|
|
863
|
+
name;
|
|
864
|
+
level;
|
|
865
|
+
batchSize;
|
|
866
|
+
flushInterval;
|
|
867
|
+
config;
|
|
868
|
+
batch = [];
|
|
869
|
+
batchTimer;
|
|
870
|
+
isReady = false;
|
|
871
|
+
/**
|
|
872
|
+
* The in-flight drain promise, or undefined when idle. addToBatch() fires
|
|
873
|
+
* flush() un-awaited on every Nth entry, so a synchronous burst can trigger
|
|
874
|
+
* many overlapping flushes. Every caller joins this single promise instead of
|
|
875
|
+
* starting its own drain, so a batch is never snapshotted and sent twice —
|
|
876
|
+
* the overlapping-flush duplication that turns N logs into N² delivered events
|
|
877
|
+
* (same class of bug fixed earlier in FileTransport / DatabaseTransport).
|
|
878
|
+
*/
|
|
879
|
+
flushPromise;
|
|
880
|
+
/** Set on the first write. Subclass fields don't exist yet while the base constructor runs. */
|
|
881
|
+
initPromise;
|
|
882
|
+
cap;
|
|
883
|
+
/** Consecutive failed drains; drives the backoff that stops a failing provider being re-sent every Nth log. */
|
|
884
|
+
failures = 0;
|
|
885
|
+
retryAt = 0;
|
|
793
886
|
constructor(name, config) {
|
|
794
|
-
this.batch = [];
|
|
795
|
-
this.isReady = false;
|
|
796
887
|
this.name = name;
|
|
797
888
|
this.config = {
|
|
798
889
|
batchSize: 50,
|
|
@@ -824,12 +915,13 @@ var AnalyticsTransport = class {
|
|
|
824
915
|
addToBatch(entry) {
|
|
825
916
|
this.batch.push(entry);
|
|
826
917
|
this.cap.enforce(this.batch);
|
|
827
|
-
|
|
828
|
-
|
|
918
|
+
const backoff = this.retryAt - Date.now();
|
|
919
|
+
if (this.batch.length >= (this.config.batchSize || 50) && backoff <= 0) this.flush().catch((err) => require_internal_log.internalError(`${this.name} batch flush failed`, err));
|
|
920
|
+
else if (!this.batchTimer && (this.config.flushInterval || backoff > 0)) {
|
|
829
921
|
var _this$batchTimer$unre, _this$batchTimer;
|
|
830
922
|
this.batchTimer = setTimeout(() => {
|
|
831
923
|
this.flush().catch((err) => require_internal_log.internalError(`${this.name} interval flush failed`, err));
|
|
832
|
-
}, this.config.flushInterval);
|
|
924
|
+
}, Math.max(this.config.flushInterval || 0, backoff));
|
|
833
925
|
(_this$batchTimer$unre = (_this$batchTimer = this.batchTimer).unref) === null || _this$batchTimer$unre === void 0 || _this$batchTimer$unre.call(_this$batchTimer);
|
|
834
926
|
}
|
|
835
927
|
}
|
|
@@ -856,7 +948,11 @@ var AnalyticsTransport = class {
|
|
|
856
948
|
this.batch = [];
|
|
857
949
|
try {
|
|
858
950
|
await this.sendBatch(entriesToSend);
|
|
951
|
+
this.failures = 0;
|
|
952
|
+
this.retryAt = 0;
|
|
859
953
|
} catch (error) {
|
|
954
|
+
this.failures += 1;
|
|
955
|
+
this.retryAt = Date.now() + Math.min(6e4, 1e3 * 2 ** (this.failures - 1));
|
|
860
956
|
require_secret_config.scrubError(error, this.secretValues());
|
|
861
957
|
require_internal_log.internalError(`Analytics transport ${this.name} flush failed`, error);
|
|
862
958
|
this.batch.unshift(...error instanceof PartialBatchError ? error.unsent : entriesToSend);
|
|
@@ -919,6 +1015,28 @@ var AnalyticsTransport = class {
|
|
|
919
1015
|
await this.ensureReady();
|
|
920
1016
|
}
|
|
921
1017
|
};
|
|
1018
|
+
// src/transports/fetch-timeout.ts
|
|
1019
|
+
/**
|
|
1020
|
+
* fetch() with a hard deadline, so an endpoint that accepts the connection and
|
|
1021
|
+
* never answers cannot hang a flush (and with it close()) forever. Uses an
|
|
1022
|
+
* AbortController rather than AbortSignal.timeout(), which needs Node 17.3+
|
|
1023
|
+
* while `engines` allows 16; the timer is unref'd so it never holds the process.
|
|
1024
|
+
*/
|
|
1025
|
+
async function fetchWithTimeout(url, init, timeoutMs = require_batch_buffer.DEFAULT_REQUEST_TIMEOUT_MS) {
|
|
1026
|
+
var _timer$unref;
|
|
1027
|
+
const controller = new AbortController();
|
|
1028
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
1029
|
+
(_timer$unref = timer.unref) === null || _timer$unref === void 0 || _timer$unref.call(timer);
|
|
1030
|
+
try {
|
|
1031
|
+
return await fetch(url, {
|
|
1032
|
+
...init,
|
|
1033
|
+
signal: controller.signal
|
|
1034
|
+
});
|
|
1035
|
+
} catch (error) {
|
|
1036
|
+
if (controller.signal.aborted) throw new Error(`Request timed out after ${timeoutMs}ms`, { cause: error });
|
|
1037
|
+
throw error;
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
922
1040
|
// src/transports/datadog.transport.ts
|
|
923
1041
|
const gzipAsync = (0, node_util.promisify)(node_zlib.gzip);
|
|
924
1042
|
const MAX_LOGS_PER_REQUEST = 1e3;
|
|
@@ -996,6 +1114,10 @@ function tag(key, value) {
|
|
|
996
1114
|
* analytics: { datadog: { apiKey: process.env.DD_API_KEY, service: 'api', env: 'production' } }
|
|
997
1115
|
*/
|
|
998
1116
|
var DataDogTransport = class extends AnalyticsTransport {
|
|
1117
|
+
datadogConfig;
|
|
1118
|
+
baseUrl;
|
|
1119
|
+
logsUrl;
|
|
1120
|
+
metricsUrl;
|
|
999
1121
|
constructor(config) {
|
|
1000
1122
|
super("datadog", config);
|
|
1001
1123
|
this.datadogConfig = config;
|
|
@@ -1154,7 +1276,7 @@ var DataDogTransport = class extends AnalyticsTransport {
|
|
|
1154
1276
|
const url = `${this.logsUrl}${endpoint}`;
|
|
1155
1277
|
try {
|
|
1156
1278
|
const compress = this.datadogConfig.compress === true;
|
|
1157
|
-
const response = await
|
|
1279
|
+
const response = await fetchWithTimeout(url, {
|
|
1158
1280
|
method: "POST",
|
|
1159
1281
|
headers: {
|
|
1160
1282
|
"Content-Type": "application/json",
|
|
@@ -1171,7 +1293,7 @@ var DataDogTransport = class extends AnalyticsTransport {
|
|
|
1171
1293
|
async makeMetricsRequest(endpoint, data) {
|
|
1172
1294
|
const url = `${this.metricsUrl}${endpoint}`;
|
|
1173
1295
|
try {
|
|
1174
|
-
const response = await
|
|
1296
|
+
const response = await fetchWithTimeout(url, {
|
|
1175
1297
|
method: "POST",
|
|
1176
1298
|
headers: {
|
|
1177
1299
|
"Content-Type": "application/json",
|
|
@@ -1216,7 +1338,7 @@ var DataDogTransport = class extends AnalyticsTransport {
|
|
|
1216
1338
|
};
|
|
1217
1339
|
const url = `${this.baseUrl}/api/v1/events`;
|
|
1218
1340
|
try {
|
|
1219
|
-
const response = await
|
|
1341
|
+
const response = await fetchWithTimeout(url, {
|
|
1220
1342
|
method: "POST",
|
|
1221
1343
|
headers: {
|
|
1222
1344
|
"Content-Type": "application/json",
|
|
@@ -1241,7 +1363,7 @@ const DEFAULT_MAX_QUEUE = 1e4;
|
|
|
1241
1363
|
const DEFAULT_FILE_MODE = 384;
|
|
1242
1364
|
const DEFAULT_DIR_MODE = 448;
|
|
1243
1365
|
function csvField(value) {
|
|
1244
|
-
return
|
|
1366
|
+
return require_csv_utils.csvField(stripControlChars(require_csv_utils.safeToString(value)), true);
|
|
1245
1367
|
}
|
|
1246
1368
|
const SIZE_UNITS = {
|
|
1247
1369
|
"": 1,
|
|
@@ -1286,21 +1408,51 @@ function formatDatePattern(date, pattern) {
|
|
|
1286
1408
|
* transports: { file: { filename: 'app.log', dirname: './logs', maxSize: '50MB' } }
|
|
1287
1409
|
*/
|
|
1288
1410
|
var FileTransport = class {
|
|
1411
|
+
name = "file";
|
|
1412
|
+
level;
|
|
1413
|
+
batchSize;
|
|
1414
|
+
flushInterval;
|
|
1415
|
+
filter;
|
|
1416
|
+
config;
|
|
1417
|
+
maxBytes;
|
|
1418
|
+
maxFiles;
|
|
1419
|
+
compress;
|
|
1420
|
+
intervalMs;
|
|
1421
|
+
timestampedActive;
|
|
1422
|
+
dir;
|
|
1423
|
+
base;
|
|
1424
|
+
ext;
|
|
1425
|
+
batch = [];
|
|
1426
|
+
batchTimer;
|
|
1427
|
+
lastRotation = /* @__PURE__ */ new Date();
|
|
1428
|
+
currentFilePath;
|
|
1429
|
+
bytesWritten = 0;
|
|
1430
|
+
period;
|
|
1431
|
+
rotateRequested = false;
|
|
1432
|
+
rotationWaiters = [];
|
|
1433
|
+
/**
|
|
1434
|
+
* The one drain loop, or undefined when idle. Only one ever runs, so the batch
|
|
1435
|
+
* is never snapshotted and written twice, and rotation (which runs inside it)
|
|
1436
|
+
* never races a write.
|
|
1437
|
+
*/
|
|
1438
|
+
draining;
|
|
1439
|
+
/** Entries queued and entries written (or failed) so far; flush() waits on these. */
|
|
1440
|
+
enqueued = 0;
|
|
1441
|
+
settled = 0;
|
|
1442
|
+
flushWaiters = [];
|
|
1443
|
+
maxQueue;
|
|
1444
|
+
fileMode;
|
|
1445
|
+
dirMode;
|
|
1446
|
+
queuePolicy;
|
|
1447
|
+
spaceWaiters = [];
|
|
1448
|
+
inFlight = 0;
|
|
1449
|
+
dropped = 0;
|
|
1450
|
+
lastDropWarning = 0;
|
|
1451
|
+
/** Gzip and pruning of rotated files run off the write path, one at a time. */
|
|
1452
|
+
housekeeping = Promise.resolve();
|
|
1453
|
+
exitListenerAttached = false;
|
|
1454
|
+
onExit = () => this.flushSyncOnExit();
|
|
1289
1455
|
constructor(config) {
|
|
1290
|
-
this.name = "file";
|
|
1291
|
-
this.batch = [];
|
|
1292
|
-
this.lastRotation = /* @__PURE__ */ new Date();
|
|
1293
|
-
this.bytesWritten = 0;
|
|
1294
|
-
this.rotateRequested = false;
|
|
1295
|
-
this.rotationWaiters = [];
|
|
1296
|
-
this.enqueued = 0;
|
|
1297
|
-
this.settled = 0;
|
|
1298
|
-
this.flushWaiters = [];
|
|
1299
|
-
this.spaceWaiters = [];
|
|
1300
|
-
this.inFlight = 0;
|
|
1301
|
-
this.dropped = 0;
|
|
1302
|
-
this.lastDropWarning = 0;
|
|
1303
|
-
this.housekeeping = Promise.resolve();
|
|
1304
1456
|
this.config = {
|
|
1305
1457
|
format: "json",
|
|
1306
1458
|
batchSize: 100,
|
|
@@ -1388,6 +1540,7 @@ var FileTransport = class {
|
|
|
1388
1540
|
await done;
|
|
1389
1541
|
}
|
|
1390
1542
|
enqueue(entry) {
|
|
1543
|
+
this.attachExitListener();
|
|
1391
1544
|
if (this.queueFull()) {
|
|
1392
1545
|
if (this.queuePolicy === "drop-oldest" && this.batch.length > 0) {
|
|
1393
1546
|
this.batch.shift();
|
|
@@ -1399,6 +1552,30 @@ var FileTransport = class {
|
|
|
1399
1552
|
this.batch.push(entry);
|
|
1400
1553
|
this.enqueued += 1;
|
|
1401
1554
|
}
|
|
1555
|
+
attachExitListener() {
|
|
1556
|
+
if (this.exitListenerAttached) return;
|
|
1557
|
+
this.exitListenerAttached = true;
|
|
1558
|
+
process.on("exit", this.onExit);
|
|
1559
|
+
}
|
|
1560
|
+
detachExitListener() {
|
|
1561
|
+
if (!this.exitListenerAttached) return;
|
|
1562
|
+
this.exitListenerAttached = false;
|
|
1563
|
+
process.removeListener("exit", this.onExit);
|
|
1564
|
+
}
|
|
1565
|
+
/**
|
|
1566
|
+
* Last chance on process exit: async writes cannot finish, so whatever is still
|
|
1567
|
+
* batched is appended synchronously to the current file.
|
|
1568
|
+
*/
|
|
1569
|
+
flushSyncOnExit() {
|
|
1570
|
+
if (this.batch.length === 0) return;
|
|
1571
|
+
const pending = this.batch;
|
|
1572
|
+
this.batch = [];
|
|
1573
|
+
this.enqueued -= pending.length;
|
|
1574
|
+
try {
|
|
1575
|
+
const content = pending.map((entry) => this.formatEntry(entry)).join("\n") + "\n";
|
|
1576
|
+
node_fs.appendFileSync(this.currentFilePath, content, { mode: this.fileMode });
|
|
1577
|
+
} catch {}
|
|
1578
|
+
}
|
|
1402
1579
|
queueFull() {
|
|
1403
1580
|
return this.batch.length + this.inFlight >= this.maxQueue;
|
|
1404
1581
|
}
|
|
@@ -1483,7 +1660,11 @@ var FileTransport = class {
|
|
|
1483
1660
|
case "json": return require_safe_stringify.stringifyForLog(require_entry_fields.mergeCoreFields({
|
|
1484
1661
|
timestamp: entry.timestamp.toISOString(),
|
|
1485
1662
|
level: entry.level,
|
|
1486
|
-
message: entry.message
|
|
1663
|
+
message: entry.message,
|
|
1664
|
+
context: entry.context,
|
|
1665
|
+
traceId: entry.traceId,
|
|
1666
|
+
appName: entry.appName,
|
|
1667
|
+
environment: entry.environment
|
|
1487
1668
|
}, entry.data));
|
|
1488
1669
|
case "csv": return [
|
|
1489
1670
|
entry.timestamp.toISOString(),
|
|
@@ -1493,7 +1674,7 @@ var FileTransport = class {
|
|
|
1493
1674
|
csvField(entry.traceId),
|
|
1494
1675
|
csvField(require_safe_stringify.stringifyForLog(entry.data || {}))
|
|
1495
1676
|
].join(",");
|
|
1496
|
-
default: return `${entry.timestamp.toISOString()} [${stripControlChars(
|
|
1677
|
+
default: return `${entry.timestamp.toISOString()} [${stripControlChars(require_csv_utils.safeToString(entry.level)).toUpperCase()}] ${stripControlChars(require_csv_utils.safeToString(entry.message))}${entry.data ? " " + require_safe_stringify.stringifyForLog(entry.data) : ""}`;
|
|
1497
1678
|
}
|
|
1498
1679
|
}
|
|
1499
1680
|
addToBatch(entry) {
|
|
@@ -1505,9 +1686,12 @@ var FileTransport = class {
|
|
|
1505
1686
|
this.batchTimer = void 0;
|
|
1506
1687
|
}
|
|
1507
1688
|
this.startDrain();
|
|
1508
|
-
} else if (!this.batchTimer && this.config.flushInterval)
|
|
1509
|
-
this.
|
|
1510
|
-
|
|
1689
|
+
} else if (!this.batchTimer && this.config.flushInterval) {
|
|
1690
|
+
this.batchTimer = setTimeout(() => {
|
|
1691
|
+
this.flush().catch((err) => require_internal_log.internalError("FileTransport interval flush failed", err));
|
|
1692
|
+
}, this.config.flushInterval);
|
|
1693
|
+
this.batchTimer.unref();
|
|
1694
|
+
}
|
|
1511
1695
|
}
|
|
1512
1696
|
/** Only ever called from drain(), so writes and rotations never overlap. */
|
|
1513
1697
|
async writeBatch(entries) {
|
|
@@ -1673,6 +1857,7 @@ var FileTransport = class {
|
|
|
1673
1857
|
this.batchTimer = void 0;
|
|
1674
1858
|
}
|
|
1675
1859
|
await this.flush();
|
|
1860
|
+
this.detachExitListener();
|
|
1676
1861
|
await this.housekeeping;
|
|
1677
1862
|
this.reportDropped(0);
|
|
1678
1863
|
}
|
|
@@ -1687,10 +1872,11 @@ var FileTransport = class {
|
|
|
1687
1872
|
* }
|
|
1688
1873
|
*/
|
|
1689
1874
|
var GoogleAnalyticsTransport = class extends AnalyticsTransport {
|
|
1875
|
+
gaConfig;
|
|
1876
|
+
baseUrl = "https://www.google-analytics.com/mp/collect";
|
|
1877
|
+
debugUrl = "https://www.google-analytics.com/debug/mp/collect";
|
|
1690
1878
|
constructor(config) {
|
|
1691
1879
|
super("google-analytics", config);
|
|
1692
|
-
this.baseUrl = "https://www.google-analytics.com/mp/collect";
|
|
1693
|
-
this.debugUrl = "https://www.google-analytics.com/debug/mp/collect";
|
|
1694
1880
|
this.gaConfig = config;
|
|
1695
1881
|
require_secret_config.protectSecrets(this, ["gaConfig"]);
|
|
1696
1882
|
}
|
|
@@ -1795,7 +1981,7 @@ var GoogleAnalyticsTransport = class extends AnalyticsTransport {
|
|
|
1795
1981
|
api_secret: this.gaConfig.apiSecret
|
|
1796
1982
|
});
|
|
1797
1983
|
try {
|
|
1798
|
-
const response = await
|
|
1984
|
+
const response = await fetchWithTimeout(`${url}?${params}`, {
|
|
1799
1985
|
method: "POST",
|
|
1800
1986
|
headers: { "Content-Type": "application/json" },
|
|
1801
1987
|
body: require_safe_stringify.stringifyForLog(payload)
|
|
@@ -1942,9 +2128,10 @@ function meetsTransportLevel(threshold, level, values) {
|
|
|
1942
2128
|
* analytics: { mixpanel: { token: process.env.MIXPANEL_TOKEN } }
|
|
1943
2129
|
*/
|
|
1944
2130
|
var MixpanelTransport = class extends AnalyticsTransport {
|
|
2131
|
+
mixpanelConfig;
|
|
2132
|
+
baseUrl = "https://api.mixpanel.com";
|
|
1945
2133
|
constructor(config) {
|
|
1946
2134
|
super("mixpanel", config);
|
|
1947
|
-
this.baseUrl = "https://api.mixpanel.com";
|
|
1948
2135
|
this.mixpanelConfig = config;
|
|
1949
2136
|
require_secret_config.protectSecrets(this, ["mixpanelConfig"]);
|
|
1950
2137
|
}
|
|
@@ -2012,7 +2199,7 @@ var MixpanelTransport = class extends AnalyticsTransport {
|
|
|
2012
2199
|
async makeRequest(endpoint, data) {
|
|
2013
2200
|
const url = `${this.mixpanelConfig.endpoint || this.baseUrl}${endpoint}`;
|
|
2014
2201
|
try {
|
|
2015
|
-
const response = await
|
|
2202
|
+
const response = await fetchWithTimeout(url, {
|
|
2016
2203
|
method: "POST",
|
|
2017
2204
|
headers: {
|
|
2018
2205
|
"Content-Type": "application/json",
|
|
@@ -2089,6 +2276,8 @@ const LOGIXIA_VERSION = "1.12.0";
|
|
|
2089
2276
|
* analytics: { segment: { writeKey: process.env.SEGMENT_WRITE_KEY } }
|
|
2090
2277
|
*/
|
|
2091
2278
|
var SegmentTransport = class extends AnalyticsTransport {
|
|
2279
|
+
segmentConfig;
|
|
2280
|
+
baseUrl;
|
|
2092
2281
|
constructor(config) {
|
|
2093
2282
|
super("segment", config);
|
|
2094
2283
|
this.segmentConfig = {
|
|
@@ -2179,7 +2368,7 @@ var SegmentTransport = class extends AnalyticsTransport {
|
|
|
2179
2368
|
const url = `${this.baseUrl}${endpoint}`;
|
|
2180
2369
|
const auth = Buffer.from(`${this.segmentConfig.writeKey}:`).toString("base64");
|
|
2181
2370
|
try {
|
|
2182
|
-
const response = await
|
|
2371
|
+
const response = await fetchWithTimeout(url, {
|
|
2183
2372
|
method: "POST",
|
|
2184
2373
|
headers: {
|
|
2185
2374
|
"Content-Type": "application/json",
|
|
@@ -2349,10 +2538,17 @@ var SegmentTransport = class extends AnalyticsTransport {
|
|
|
2349
2538
|
}
|
|
2350
2539
|
};
|
|
2351
2540
|
// src/transports/transport.manager.ts
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
}
|
|
2541
|
+
const DEFAULT_MAX_PENDING_RETRIES = 1e3;
|
|
2542
|
+
const RETRY_WARN_INTERVAL_MS = 5e3;
|
|
2355
2543
|
var TransportManager = class extends node_events.EventEmitter {
|
|
2544
|
+
transports = /* @__PURE__ */ new Map();
|
|
2545
|
+
metrics = /* @__PURE__ */ new Map();
|
|
2546
|
+
isShuttingDown = false;
|
|
2547
|
+
transportLevelPreferences = /* @__PURE__ */ new Map();
|
|
2548
|
+
warnedPromptDeprecated = false;
|
|
2549
|
+
closePromise;
|
|
2550
|
+
retryStates = /* @__PURE__ */ new Map();
|
|
2551
|
+
levelValues;
|
|
2356
2552
|
/**
|
|
2357
2553
|
* @param config Transport configuration.
|
|
2358
2554
|
* @param levels The logger's `levelOptions.levels`; used with the built-in levels
|
|
@@ -2360,11 +2556,6 @@ var TransportManager = class extends node_events.EventEmitter {
|
|
|
2360
2556
|
*/
|
|
2361
2557
|
constructor(config = {}, levels) {
|
|
2362
2558
|
super();
|
|
2363
|
-
this.transports = /* @__PURE__ */ new Map();
|
|
2364
|
-
this.metrics = /* @__PURE__ */ new Map();
|
|
2365
|
-
this.isShuttingDown = false;
|
|
2366
|
-
this.transportLevelPreferences = /* @__PURE__ */ new Map();
|
|
2367
|
-
this.warnedPromptDeprecated = false;
|
|
2368
2559
|
this.levelValues = buildLevelValues(levels);
|
|
2369
2560
|
this.setupTransports(config);
|
|
2370
2561
|
}
|
|
@@ -2437,8 +2628,9 @@ var TransportManager = class extends node_events.EventEmitter {
|
|
|
2437
2628
|
if (!transport) return false;
|
|
2438
2629
|
this.transports.delete(id);
|
|
2439
2630
|
this.metrics.delete(id);
|
|
2631
|
+
this.drainRetries(id, transport);
|
|
2440
2632
|
if (transport.close) transport.close().catch((error) => {
|
|
2441
|
-
|
|
2633
|
+
require_internal_log.internalError(`Transport "${id}" failed to close`, error);
|
|
2442
2634
|
});
|
|
2443
2635
|
this.emit("transport:removed", id);
|
|
2444
2636
|
return true;
|
|
@@ -2454,7 +2646,10 @@ var TransportManager = class extends node_events.EventEmitter {
|
|
|
2454
2646
|
* sync path.
|
|
2455
2647
|
*/
|
|
2456
2648
|
write(entry) {
|
|
2457
|
-
if (this.isShuttingDown)
|
|
2649
|
+
if (this.isShuttingDown) {
|
|
2650
|
+
this.writeAfterClose(entry);
|
|
2651
|
+
return;
|
|
2652
|
+
}
|
|
2458
2653
|
const transportEntry = {
|
|
2459
2654
|
timestamp: typeof entry.timestamp === "string" ? new Date(entry.timestamp) : entry.timestamp,
|
|
2460
2655
|
level: entry.level,
|
|
@@ -2492,6 +2687,27 @@ var TransportManager = class extends node_events.EventEmitter {
|
|
|
2492
2687
|
}
|
|
2493
2688
|
});
|
|
2494
2689
|
}
|
|
2690
|
+
/**
|
|
2691
|
+
* Transports are gone once closed, but the app may still log (its own signal
|
|
2692
|
+
* handler, a late async callback). Emit such lines on stdout/stderr rather
|
|
2693
|
+
* than losing them silently.
|
|
2694
|
+
*/
|
|
2695
|
+
writeAfterClose(entry) {
|
|
2696
|
+
const line = `${require_safe_stringify.stringifyForLog({
|
|
2697
|
+
timestamp: entry.timestamp,
|
|
2698
|
+
level: entry.level,
|
|
2699
|
+
message: entry.message,
|
|
2700
|
+
appName: entry.appName,
|
|
2701
|
+
context: entry.context,
|
|
2702
|
+
traceId: entry.traceId,
|
|
2703
|
+
...entry.payload
|
|
2704
|
+
})}\n`;
|
|
2705
|
+
const level = String(entry.level).toLowerCase();
|
|
2706
|
+
const stream = level === "error" || level === "warn" ? "stderr" : "stdout";
|
|
2707
|
+
try {
|
|
2708
|
+
process[stream].write(line);
|
|
2709
|
+
} catch {}
|
|
2710
|
+
}
|
|
2495
2711
|
writeToTransport(id, transport, entry) {
|
|
2496
2712
|
const startTime = Date.now();
|
|
2497
2713
|
const metrics = this.metrics.get(id);
|
|
@@ -2518,43 +2734,86 @@ var TransportManager = class extends node_events.EventEmitter {
|
|
|
2518
2734
|
onSuccess();
|
|
2519
2735
|
return;
|
|
2520
2736
|
}
|
|
2521
|
-
return this._writeWithRetry(transport, entry).then(
|
|
2737
|
+
return this._writeWithRetry(id, transport, entry).then((written) => {
|
|
2738
|
+
if (written) onSuccess();
|
|
2739
|
+
}, onError);
|
|
2522
2740
|
}
|
|
2523
2741
|
/**
|
|
2524
2742
|
* Feature 9: Multi-transport retry + failover.
|
|
2525
2743
|
*
|
|
2526
|
-
*
|
|
2527
|
-
*
|
|
2528
|
-
*
|
|
2744
|
+
* The first attempt is awaited by the caller. If it fails, the entry moves to
|
|
2745
|
+
* a bounded per-transport retry queue and the caller's promise resolves, so a
|
|
2746
|
+
* down transport never holds a log call across backoff. The queue retries up
|
|
2747
|
+
* to `retry.maxRetries` more times with the configured backoff, then routes
|
|
2748
|
+
* the entry to the fallback transport (if any) and calls `onExhausted`.
|
|
2749
|
+
* Returns true when the first attempt succeeded.
|
|
2529
2750
|
*/
|
|
2530
|
-
async _writeWithRetry(transport, entry) {
|
|
2531
|
-
|
|
2532
|
-
if (!retryCfg || !retryCfg.maxRetries) {
|
|
2751
|
+
async _writeWithRetry(id, transport, entry) {
|
|
2752
|
+
try {
|
|
2533
2753
|
await transport.write(entry);
|
|
2534
|
-
return;
|
|
2754
|
+
return true;
|
|
2755
|
+
} catch (err) {
|
|
2756
|
+
this.enqueueRetry(id, transport, entry, err instanceof Error ? err : new Error(String(err)));
|
|
2757
|
+
return false;
|
|
2535
2758
|
}
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2759
|
+
}
|
|
2760
|
+
enqueueRetry(id, transport, entry, error) {
|
|
2761
|
+
let state = this.retryStates.get(id);
|
|
2762
|
+
if (!state) {
|
|
2763
|
+
state = {
|
|
2764
|
+
queue: [],
|
|
2765
|
+
timer: void 0,
|
|
2766
|
+
running: false,
|
|
2767
|
+
dropped: 0,
|
|
2768
|
+
lastWarn: 0
|
|
2769
|
+
};
|
|
2770
|
+
this.retryStates.set(id, state);
|
|
2771
|
+
}
|
|
2772
|
+
const maxPending = transport.retry.maxPending ?? DEFAULT_MAX_PENDING_RETRIES;
|
|
2773
|
+
while (state.queue.length >= maxPending) {
|
|
2774
|
+
state.queue.shift();
|
|
2775
|
+
state.dropped++;
|
|
2776
|
+
}
|
|
2777
|
+
this.warnDropped(id, state);
|
|
2778
|
+
this.scheduleRetry(id, transport, state, {
|
|
2779
|
+
entry,
|
|
2780
|
+
attempt: 0,
|
|
2781
|
+
due: 0
|
|
2782
|
+
}, error);
|
|
2783
|
+
this.pumpRetries(id, transport, state);
|
|
2784
|
+
}
|
|
2785
|
+
warnDropped(id, state) {
|
|
2786
|
+
const now = Date.now();
|
|
2787
|
+
if (state.dropped > 0 && now - state.lastWarn >= RETRY_WARN_INTERVAL_MS) {
|
|
2788
|
+
require_internal_log.internalWarn(`TransportManager: retry queue for "${id}" is full; dropped ${state.dropped} oldest log entr${state.dropped === 1 ? "y" : "ies"}`);
|
|
2789
|
+
state.dropped = 0;
|
|
2790
|
+
state.lastWarn = now;
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
/** Queues `item` for its next attempt, or finishes it when retries ran out. */
|
|
2794
|
+
scheduleRetry(id, transport, state, item, error) {
|
|
2795
|
+
const { maxRetries = 0, backoff = "exponential", delay = 500, maxDelay = 3e4 } = transport.retry;
|
|
2796
|
+
if (item.attempt >= maxRetries) {
|
|
2797
|
+
this.exhaust(id, transport, item.entry, error);
|
|
2540
2798
|
return;
|
|
2541
|
-
} catch (err) {
|
|
2542
|
-
lastError = err instanceof Error ? err : new Error(String(err));
|
|
2543
|
-
if (attempt < maxRetries) {
|
|
2544
|
-
let wait;
|
|
2545
|
-
switch (backoff) {
|
|
2546
|
-
case "fixed":
|
|
2547
|
-
wait = baseDelay;
|
|
2548
|
-
break;
|
|
2549
|
-
case "linear":
|
|
2550
|
-
wait = baseDelay * (attempt + 1);
|
|
2551
|
-
break;
|
|
2552
|
-
default: wait = Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
|
|
2553
|
-
}
|
|
2554
|
-
this.emit("transport:retry", transport.name, attempt + 1, maxRetries, wait);
|
|
2555
|
-
await _sleep(wait);
|
|
2556
|
-
}
|
|
2557
2799
|
}
|
|
2800
|
+
let wait;
|
|
2801
|
+
switch (backoff) {
|
|
2802
|
+
case "fixed":
|
|
2803
|
+
wait = delay;
|
|
2804
|
+
break;
|
|
2805
|
+
case "linear":
|
|
2806
|
+
wait = delay * (item.attempt + 1);
|
|
2807
|
+
break;
|
|
2808
|
+
default: wait = Math.min(delay * Math.pow(2, item.attempt), maxDelay);
|
|
2809
|
+
}
|
|
2810
|
+
item.attempt++;
|
|
2811
|
+
item.due = Date.now() + wait;
|
|
2812
|
+
state.queue.push(item);
|
|
2813
|
+
this.emit("transport:retry", transport.name, item.attempt, maxRetries, wait);
|
|
2814
|
+
}
|
|
2815
|
+
async exhaust(id, transport, entry, error) {
|
|
2816
|
+
const { fallback, onExhausted } = transport.retry;
|
|
2558
2817
|
if (fallback) {
|
|
2559
2818
|
this.emit("transport:fallback", transport.name, fallback.name);
|
|
2560
2819
|
try {
|
|
@@ -2562,8 +2821,65 @@ var TransportManager = class extends node_events.EventEmitter {
|
|
|
2562
2821
|
return;
|
|
2563
2822
|
} catch {}
|
|
2564
2823
|
}
|
|
2565
|
-
|
|
2566
|
-
|
|
2824
|
+
const metrics = this.metrics.get(id);
|
|
2825
|
+
if (metrics) metrics.errors++;
|
|
2826
|
+
try {
|
|
2827
|
+
onExhausted === null || onExhausted === void 0 || onExhausted(error, entry);
|
|
2828
|
+
} catch (hookError) {
|
|
2829
|
+
require_internal_log.internalWarn(`TransportManager: onExhausted for "${id}" threw: ${String(hookError)}`);
|
|
2830
|
+
}
|
|
2831
|
+
if (this.listenerCount("error") > 0) this.emit("error", error, id);
|
|
2832
|
+
}
|
|
2833
|
+
/** One serial worker per transport: the earliest-due entry is retried first. */
|
|
2834
|
+
pumpRetries(id, transport, state) {
|
|
2835
|
+
var _state$timer$unref, _state$timer;
|
|
2836
|
+
if (state.running || state.timer || state.queue.length === 0) return;
|
|
2837
|
+
let next = 0;
|
|
2838
|
+
for (let i = 1; i < state.queue.length; i++) if (state.queue[i].due < state.queue[next].due) next = i;
|
|
2839
|
+
const wait = Math.max(0, state.queue[next].due - Date.now());
|
|
2840
|
+
state.timer = setTimeout(() => {
|
|
2841
|
+
state.timer = void 0;
|
|
2842
|
+
this.runRetry(id, transport, state);
|
|
2843
|
+
}, wait);
|
|
2844
|
+
(_state$timer$unref = (_state$timer = state.timer).unref) === null || _state$timer$unref === void 0 || _state$timer$unref.call(_state$timer);
|
|
2845
|
+
}
|
|
2846
|
+
async runRetry(id, transport, state) {
|
|
2847
|
+
if (state.queue.length === 0) return;
|
|
2848
|
+
let next = 0;
|
|
2849
|
+
for (let i = 1; i < state.queue.length; i++) if (state.queue[i].due < state.queue[next].due) next = i;
|
|
2850
|
+
const [item] = state.queue.splice(next, 1);
|
|
2851
|
+
if (!item) return;
|
|
2852
|
+
state.running = true;
|
|
2853
|
+
try {
|
|
2854
|
+
await transport.write(item.entry);
|
|
2855
|
+
const metrics = this.metrics.get(id);
|
|
2856
|
+
if (metrics) {
|
|
2857
|
+
metrics.logsWritten++;
|
|
2858
|
+
metrics.lastWrite = /* @__PURE__ */ new Date();
|
|
2859
|
+
}
|
|
2860
|
+
this.emit("log", item.entry);
|
|
2861
|
+
} catch (err) {
|
|
2862
|
+
this.scheduleRetry(id, transport, state, item, err instanceof Error ? err : new Error(String(err)));
|
|
2863
|
+
} finally {
|
|
2864
|
+
state.running = false;
|
|
2865
|
+
}
|
|
2866
|
+
if (!this.isShuttingDown) this.pumpRetries(id, transport, state);
|
|
2867
|
+
}
|
|
2868
|
+
/** Stops a transport's retry worker and hands what is still queued to its fallback. */
|
|
2869
|
+
async drainRetries(id, transport) {
|
|
2870
|
+
var _transport$retry;
|
|
2871
|
+
const state = this.retryStates.get(id);
|
|
2872
|
+
if (!state) return;
|
|
2873
|
+
this.retryStates.delete(id);
|
|
2874
|
+
if (state.timer) clearTimeout(state.timer);
|
|
2875
|
+
state.timer = void 0;
|
|
2876
|
+
const fallback = transport === null || transport === void 0 || (_transport$retry = transport.retry) === null || _transport$retry === void 0 ? void 0 : _transport$retry.fallback;
|
|
2877
|
+
if (state.queue.length === 0) return;
|
|
2878
|
+
if (!fallback) {
|
|
2879
|
+
require_internal_log.internalWarn(`TransportManager: "${id}" closed with ${state.queue.length} log entr${state.queue.length === 1 ? "y" : "ies"} still awaiting retry`);
|
|
2880
|
+
return;
|
|
2881
|
+
}
|
|
2882
|
+
await Promise.allSettled(state.queue.map((item) => fallback.write(item.entry)));
|
|
2567
2883
|
}
|
|
2568
2884
|
shouldTransportHandle(transport, level, transportId) {
|
|
2569
2885
|
if (transportId && this.transportLevelPreferences.has(transportId)) return this.transportLevelPreferences.get(transportId).includes(level.toLowerCase());
|
|
@@ -2582,19 +2898,35 @@ var TransportManager = class extends node_events.EventEmitter {
|
|
|
2582
2898
|
if (readyPromises.length > 0) await Promise.all(readyPromises);
|
|
2583
2899
|
}
|
|
2584
2900
|
async flush() {
|
|
2901
|
+
await this.flushTransports(false);
|
|
2902
|
+
}
|
|
2903
|
+
/**
|
|
2904
|
+
* @param skipClosable Leave out transports with a close(): close() flushes
|
|
2905
|
+
* them itself, and a second flush first would double the time a hung
|
|
2906
|
+
* endpoint can hold shutdown.
|
|
2907
|
+
*/
|
|
2908
|
+
async flushTransports(skipClosable) {
|
|
2585
2909
|
const flushPromises = [];
|
|
2586
|
-
for (const [id, transport] of this.transports)
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2910
|
+
for (const [id, transport] of this.transports) {
|
|
2911
|
+
if (skipClosable && transport.close) continue;
|
|
2912
|
+
if (this.isBatchTransport(transport)) {
|
|
2913
|
+
const flushPromise = transport.flush().catch((error) => {
|
|
2914
|
+
this.emit("error", error, id);
|
|
2915
|
+
});
|
|
2916
|
+
flushPromises.push(flushPromise);
|
|
2917
|
+
}
|
|
2591
2918
|
}
|
|
2592
2919
|
await Promise.allSettled(flushPromises);
|
|
2593
2920
|
this.emit("flush", "all", this.transports.size);
|
|
2594
2921
|
}
|
|
2595
|
-
|
|
2596
|
-
|
|
2922
|
+
close() {
|
|
2923
|
+
this.closePromise ??= this.closeOnce();
|
|
2924
|
+
return this.closePromise;
|
|
2925
|
+
}
|
|
2926
|
+
async closeOnce() {
|
|
2927
|
+
await this.flushTransports(true);
|
|
2597
2928
|
this.isShuttingDown = true;
|
|
2929
|
+
await Promise.allSettled([...this.retryStates.keys()].map((id) => this.drainRetries(id, this.transports.get(id))));
|
|
2598
2930
|
const closePromises = [];
|
|
2599
2931
|
for (const [id, transport] of this.transports) if (transport.close) {
|
|
2600
2932
|
const closePromise = transport.close().catch((error) => {
|
|
@@ -2918,4 +3250,4 @@ Object.defineProperty(exports, "stripControlChars", {
|
|
|
2918
3250
|
}
|
|
2919
3251
|
});
|
|
2920
3252
|
|
|
2921
|
-
//# sourceMappingURL=otel-
|
|
3253
|
+
//# sourceMappingURL=otel-8ypFGG19.js.map
|