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