autotel 2.22.0 → 2.23.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 +112 -6
- package/dist/auto.cjs +3 -3
- package/dist/auto.js +2 -2
- package/dist/{chunk-EWH2542B.js → chunk-3AMR5XLZ.js} +3 -3
- package/dist/{chunk-EWH2542B.js.map → chunk-3AMR5XLZ.js.map} +1 -1
- package/dist/chunk-3QXBFGKP.js +344 -0
- package/dist/chunk-3QXBFGKP.js.map +1 -0
- package/dist/{chunk-VQFF2WMP.cjs → chunk-3ZFDJJWZ.cjs} +37 -29
- package/dist/chunk-3ZFDJJWZ.cjs.map +1 -0
- package/dist/{chunk-CQC6RVLR.cjs → chunk-4RZ4JUBY.cjs} +5 -5
- package/dist/{chunk-CQC6RVLR.cjs.map → chunk-4RZ4JUBY.cjs.map} +1 -1
- package/dist/{chunk-PAVYKPCQ.js → chunk-5XUEHX7J.js} +3 -3
- package/dist/{chunk-PAVYKPCQ.js.map → chunk-5XUEHX7J.js.map} +1 -1
- package/dist/chunk-6S5RUKU3.cjs +347 -0
- package/dist/chunk-6S5RUKU3.cjs.map +1 -0
- package/dist/{chunk-BS757SL2.js → chunk-724XLWR3.js} +9 -4
- package/dist/chunk-724XLWR3.js.map +1 -0
- package/dist/chunk-7EQ4G4SI.cjs +146 -0
- package/dist/chunk-7EQ4G4SI.cjs.map +1 -0
- package/dist/{chunk-CQP5SQT4.cjs → chunk-AXFWWJF3.cjs} +7 -7
- package/dist/{chunk-CQP5SQT4.cjs.map → chunk-AXFWWJF3.cjs.map} +1 -1
- package/dist/{chunk-7NH625MS.cjs → chunk-BSZP4URK.cjs} +5 -5
- package/dist/{chunk-7NH625MS.cjs.map → chunk-BSZP4URK.cjs.map} +1 -1
- package/dist/{chunk-GZFH6P5U.js → chunk-GY4CRZSV.js} +14 -6
- package/dist/chunk-GY4CRZSV.js.map +1 -0
- package/dist/{chunk-QKUGUDXJ.cjs → chunk-HSEIUH7F.cjs} +10 -5
- package/dist/chunk-HSEIUH7F.cjs.map +1 -0
- package/dist/{chunk-DTW3WB7Z.js → chunk-IPKXURBW.js} +3 -3
- package/dist/{chunk-DTW3WB7Z.js.map → chunk-IPKXURBW.js.map} +1 -1
- package/dist/chunk-J7VGRIAJ.js +64 -0
- package/dist/chunk-J7VGRIAJ.js.map +1 -0
- package/dist/chunk-KFOHQK7X.js +144 -0
- package/dist/chunk-KFOHQK7X.js.map +1 -0
- package/dist/{chunk-4UYR46UP.cjs → chunk-MSUHW2I4.cjs} +13 -13
- package/dist/{chunk-4UYR46UP.cjs.map → chunk-MSUHW2I4.cjs.map} +1 -1
- package/dist/chunk-T4B5LB6E.cjs +66 -0
- package/dist/chunk-T4B5LB6E.cjs.map +1 -0
- package/dist/{chunk-QHT4MUED.js → chunk-WCIIFRGL.js} +3 -3
- package/dist/{chunk-QHT4MUED.js.map → chunk-WCIIFRGL.js.map} +1 -1
- package/dist/decorators.cjs +3 -3
- package/dist/decorators.js +3 -3
- package/dist/drain-pipeline.cjs +13 -0
- package/dist/drain-pipeline.cjs.map +1 -0
- package/dist/drain-pipeline.d.cts +37 -0
- package/dist/drain-pipeline.d.ts +37 -0
- package/dist/drain-pipeline.js +4 -0
- package/dist/drain-pipeline.js.map +1 -0
- package/dist/event.cjs +6 -6
- package/dist/event.js +3 -3
- package/dist/functional.cjs +10 -10
- package/dist/functional.js +3 -3
- package/dist/index.cjs +256 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +72 -3
- package/dist/index.d.ts +72 -3
- package/dist/index.js +210 -11
- package/dist/index.js.map +1 -1
- package/dist/{init-BMiXSJNM.d.cts → init-BC5aN8bh.d.cts} +18 -0
- package/dist/{init-ByRbNTRo.d.ts → init-_FG4IbhF.d.ts} +18 -0
- package/dist/instrumentation.cjs +9 -9
- package/dist/instrumentation.js +2 -2
- package/dist/messaging.cjs +7 -7
- package/dist/messaging.js +4 -4
- package/dist/parse-error.cjs +13 -0
- package/dist/parse-error.cjs.map +1 -0
- package/dist/parse-error.d.cts +13 -0
- package/dist/parse-error.d.ts +13 -0
- package/dist/parse-error.js +4 -0
- package/dist/parse-error.js.map +1 -0
- package/dist/processors.cjs +2 -2
- package/dist/processors.d.cts +40 -4
- package/dist/processors.d.ts +40 -4
- package/dist/processors.js +1 -1
- package/dist/semantic-helpers.cjs +8 -8
- package/dist/semantic-helpers.js +4 -4
- package/dist/webhook.cjs +4 -4
- package/dist/webhook.js +3 -3
- package/dist/workflow-distributed.cjs +5 -5
- package/dist/workflow-distributed.js +3 -3
- package/dist/workflow.cjs +8 -8
- package/dist/workflow.js +4 -4
- package/dist/yaml-config.d.cts +2 -1
- package/dist/yaml-config.d.ts +2 -1
- package/package.json +11 -1
- package/src/drain-pipeline.test.ts +68 -0
- package/src/drain-pipeline.ts +199 -0
- package/src/flatten-attributes.test.ts +76 -0
- package/src/flatten-attributes.ts +80 -0
- package/src/functional.test.ts +63 -0
- package/src/functional.ts +11 -3
- package/src/index.ts +33 -0
- package/src/init.ts +22 -0
- package/src/parse-error.test.ts +73 -0
- package/src/parse-error.ts +112 -0
- package/src/pretty-log-formatter.test.ts +123 -0
- package/src/pretty-log-formatter.ts +210 -0
- package/src/processors/canonical-log-line-processor.test.ts +81 -25
- package/src/processors/canonical-log-line-processor.ts +130 -42
- package/src/request-logger.test.ts +124 -0
- package/src/request-logger.ts +140 -0
- package/src/structured-error.test.ts +76 -0
- package/src/structured-error.ts +86 -0
- package/dist/chunk-2RQDNGV3.js +0 -126
- package/dist/chunk-2RQDNGV3.js.map +0 -1
- package/dist/chunk-BS757SL2.js.map +0 -1
- package/dist/chunk-GZFH6P5U.js.map +0 -1
- package/dist/chunk-ONK2Y22L.cjs +0 -128
- package/dist/chunk-ONK2Y22L.cjs.map +0 -1
- package/dist/chunk-QKUGUDXJ.cjs.map +0 -1
- package/dist/chunk-VQFF2WMP.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,31 +1,33 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk7EQ4G4SI_cjs = require('./chunk-7EQ4G4SI.cjs');
|
|
4
|
+
var chunkBSZP4URK_cjs = require('./chunk-BSZP4URK.cjs');
|
|
4
5
|
var chunkXRBP4RYL_cjs = require('./chunk-XRBP4RYL.cjs');
|
|
5
6
|
var chunk2ZKEORFN_cjs = require('./chunk-2ZKEORFN.cjs');
|
|
6
7
|
var chunkESMHTKLJ_cjs = require('./chunk-ESMHTKLJ.cjs');
|
|
7
|
-
var
|
|
8
|
+
var chunkT4B5LB6E_cjs = require('./chunk-T4B5LB6E.cjs');
|
|
9
|
+
var chunk4RZ4JUBY_cjs = require('./chunk-4RZ4JUBY.cjs');
|
|
8
10
|
var chunkINJD3G4K_cjs = require('./chunk-INJD3G4K.cjs');
|
|
9
11
|
var chunkTC5ZPWM4_cjs = require('./chunk-TC5ZPWM4.cjs');
|
|
10
12
|
require('./chunk-YTXEZ4SD.cjs');
|
|
11
13
|
var chunkWJH6IYU2_cjs = require('./chunk-WJH6IYU2.cjs');
|
|
12
|
-
var
|
|
13
|
-
var
|
|
14
|
+
var chunkAXFWWJF3_cjs = require('./chunk-AXFWWJF3.cjs');
|
|
15
|
+
var chunk3ZFDJJWZ_cjs = require('./chunk-3ZFDJJWZ.cjs');
|
|
14
16
|
var chunkW4EUTSB2_cjs = require('./chunk-W4EUTSB2.cjs');
|
|
15
17
|
var chunkGML3FBOT_cjs = require('./chunk-GML3FBOT.cjs');
|
|
16
|
-
var
|
|
18
|
+
var chunkMSUHW2I4_cjs = require('./chunk-MSUHW2I4.cjs');
|
|
17
19
|
require('./chunk-NZ72VDNY.cjs');
|
|
18
20
|
require('./chunk-UY3UYPBZ.cjs');
|
|
19
21
|
var chunkD5LMF53P_cjs = require('./chunk-D5LMF53P.cjs');
|
|
20
22
|
var chunkXRKAL7WJ_cjs = require('./chunk-XRKAL7WJ.cjs');
|
|
21
|
-
var
|
|
23
|
+
var chunkHSEIUH7F_cjs = require('./chunk-HSEIUH7F.cjs');
|
|
22
24
|
require('./chunk-6YIDHH2S.cjs');
|
|
23
25
|
require('./chunk-GVLK7YUU.cjs');
|
|
24
26
|
var chunkZNMBW67B_cjs = require('./chunk-ZNMBW67B.cjs');
|
|
25
27
|
var chunkIOYFAFHJ_cjs = require('./chunk-IOYFAFHJ.cjs');
|
|
26
28
|
var chunkELW34S4C_cjs = require('./chunk-ELW34S4C.cjs');
|
|
27
29
|
require('./chunk-CU6IDACR.cjs');
|
|
28
|
-
require('./chunk-
|
|
30
|
+
var chunk6S5RUKU3_cjs = require('./chunk-6S5RUKU3.cjs');
|
|
29
31
|
require('./chunk-YS6C2YJE.cjs');
|
|
30
32
|
var chunkBGVKKL2N_cjs = require('./chunk-BGVKKL2N.cjs');
|
|
31
33
|
require('./chunk-AZ24DJAG.cjs');
|
|
@@ -39,7 +41,7 @@ async function flush(options) {
|
|
|
39
41
|
const timeout = options?.timeout ?? 2e3;
|
|
40
42
|
const forShutdown = options?.forShutdown ?? false;
|
|
41
43
|
const doFlush = async () => {
|
|
42
|
-
const eventsQueue =
|
|
44
|
+
const eventsQueue = chunk3ZFDJJWZ_cjs.getEventQueue();
|
|
43
45
|
if (eventsQueue) {
|
|
44
46
|
if (forShutdown) {
|
|
45
47
|
await eventsQueue.shutdown();
|
|
@@ -47,7 +49,7 @@ async function flush(options) {
|
|
|
47
49
|
await eventsQueue.flush();
|
|
48
50
|
}
|
|
49
51
|
}
|
|
50
|
-
const sdk =
|
|
52
|
+
const sdk = chunkHSEIUH7F_cjs.getSdk();
|
|
51
53
|
if (sdk) {
|
|
52
54
|
try {
|
|
53
55
|
const sdkAny = sdk;
|
|
@@ -81,7 +83,7 @@ async function flush(options) {
|
|
|
81
83
|
if (timeoutHandle) {
|
|
82
84
|
clearTimeout(timeoutHandle);
|
|
83
85
|
}
|
|
84
|
-
const logger =
|
|
86
|
+
const logger = chunkHSEIUH7F_cjs.getLogger();
|
|
85
87
|
logger.error(
|
|
86
88
|
{
|
|
87
89
|
err: error instanceof Error ? error : new Error(String(error))
|
|
@@ -92,7 +94,7 @@ async function flush(options) {
|
|
|
92
94
|
}
|
|
93
95
|
}
|
|
94
96
|
async function shutdown() {
|
|
95
|
-
const logger =
|
|
97
|
+
const logger = chunkHSEIUH7F_cjs.getLogger();
|
|
96
98
|
let shutdownError = null;
|
|
97
99
|
try {
|
|
98
100
|
await flush({ forShutdown: true });
|
|
@@ -107,7 +109,7 @@ async function shutdown() {
|
|
|
107
109
|
);
|
|
108
110
|
}
|
|
109
111
|
try {
|
|
110
|
-
const sdk =
|
|
112
|
+
const sdk = chunkHSEIUH7F_cjs.getSdk();
|
|
111
113
|
if (sdk) {
|
|
112
114
|
await sdk.shutdown();
|
|
113
115
|
}
|
|
@@ -121,13 +123,13 @@ async function shutdown() {
|
|
|
121
123
|
logger.error({ err }, "[autotel] SDK shutdown failed");
|
|
122
124
|
}
|
|
123
125
|
} finally {
|
|
124
|
-
const eventsQueue =
|
|
126
|
+
const eventsQueue = chunk3ZFDJJWZ_cjs.getEventQueue();
|
|
125
127
|
if (eventsQueue && typeof eventsQueue.cleanup === "function") {
|
|
126
128
|
eventsQueue.cleanup();
|
|
127
129
|
}
|
|
128
|
-
|
|
130
|
+
chunkMSUHW2I4_cjs.resetEvents();
|
|
129
131
|
chunkTC5ZPWM4_cjs.resetMetrics();
|
|
130
|
-
|
|
132
|
+
chunk3ZFDJJWZ_cjs.resetEventQueue();
|
|
131
133
|
}
|
|
132
134
|
if (shutdownError) {
|
|
133
135
|
throw shutdownError;
|
|
@@ -142,7 +144,7 @@ function registerShutdownHooks() {
|
|
|
142
144
|
if (shuttingDown) return;
|
|
143
145
|
shuttingDown = true;
|
|
144
146
|
if (process.env.NODE_ENV !== "test") {
|
|
145
|
-
|
|
147
|
+
chunkHSEIUH7F_cjs.getLogger().info(
|
|
146
148
|
{},
|
|
147
149
|
`[autotel] Received ${signal}, flushing telemetry...`
|
|
148
150
|
);
|
|
@@ -150,7 +152,7 @@ function registerShutdownHooks() {
|
|
|
150
152
|
try {
|
|
151
153
|
await shutdown();
|
|
152
154
|
} catch (error) {
|
|
153
|
-
|
|
155
|
+
chunkHSEIUH7F_cjs.getLogger().error(
|
|
154
156
|
{
|
|
155
157
|
err: error instanceof Error ? error : void 0
|
|
156
158
|
},
|
|
@@ -164,21 +166,220 @@ function registerShutdownHooks() {
|
|
|
164
166
|
}
|
|
165
167
|
registerShutdownHooks();
|
|
166
168
|
|
|
169
|
+
// src/flatten-attributes.ts
|
|
170
|
+
function toAttributeValue(value) {
|
|
171
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
172
|
+
return value;
|
|
173
|
+
}
|
|
174
|
+
if (Array.isArray(value)) {
|
|
175
|
+
if (value.every((v) => typeof v === "string") || value.every((v) => typeof v === "number") || value.every((v) => typeof v === "boolean")) {
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
return JSON.stringify(value);
|
|
180
|
+
} catch {
|
|
181
|
+
return "<serialization-failed>";
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (value instanceof Date) {
|
|
185
|
+
return value.toISOString();
|
|
186
|
+
}
|
|
187
|
+
if (value instanceof Error) {
|
|
188
|
+
return value.message;
|
|
189
|
+
}
|
|
190
|
+
return void 0;
|
|
191
|
+
}
|
|
192
|
+
function flattenToAttributes(fields, prefix = "") {
|
|
193
|
+
const out = {};
|
|
194
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
195
|
+
function flatten(obj, currentPrefix) {
|
|
196
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
197
|
+
if (value == null) continue;
|
|
198
|
+
const nextKey = currentPrefix ? `${currentPrefix}.${key}` : key;
|
|
199
|
+
const attr = toAttributeValue(value);
|
|
200
|
+
if (attr !== void 0) {
|
|
201
|
+
out[nextKey] = attr;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (typeof value === "object" && value.constructor === Object) {
|
|
205
|
+
if (seen.has(value)) {
|
|
206
|
+
out[nextKey] = "<circular-reference>";
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
seen.add(value);
|
|
210
|
+
flatten(value, nextKey);
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
out[nextKey] = JSON.stringify(value);
|
|
215
|
+
} catch {
|
|
216
|
+
out[nextKey] = "<serialization-failed>";
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
flatten(fields, prefix);
|
|
221
|
+
return out;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// src/structured-error.ts
|
|
225
|
+
function createStructuredError(input) {
|
|
226
|
+
const error = new Error(input.message, {
|
|
227
|
+
cause: input.cause
|
|
228
|
+
});
|
|
229
|
+
error.name = input.name ?? "StructuredError";
|
|
230
|
+
if (input.why !== void 0) error.why = input.why;
|
|
231
|
+
if (input.fix !== void 0) error.fix = input.fix;
|
|
232
|
+
if (input.link !== void 0) error.link = input.link;
|
|
233
|
+
if (input.code !== void 0) error.code = input.code;
|
|
234
|
+
if (input.status !== void 0) error.status = input.status;
|
|
235
|
+
if (input.details !== void 0) error.details = input.details;
|
|
236
|
+
return error;
|
|
237
|
+
}
|
|
238
|
+
function getStructuredErrorAttributes(error) {
|
|
239
|
+
const structured = error;
|
|
240
|
+
const attributes = {
|
|
241
|
+
"error.type": error.name || "Error",
|
|
242
|
+
"error.message": error.message
|
|
243
|
+
};
|
|
244
|
+
if (error.stack) attributes["error.stack"] = error.stack;
|
|
245
|
+
if (structured.why) attributes["error.why"] = structured.why;
|
|
246
|
+
if (structured.fix) attributes["error.fix"] = structured.fix;
|
|
247
|
+
if (structured.link) attributes["error.link"] = structured.link;
|
|
248
|
+
if (structured.code !== void 0) {
|
|
249
|
+
attributes["error.code"] = typeof structured.code === "string" ? structured.code : String(structured.code);
|
|
250
|
+
}
|
|
251
|
+
if (structured.status !== void 0) {
|
|
252
|
+
attributes["error.status"] = structured.status;
|
|
253
|
+
}
|
|
254
|
+
if (structured.details) {
|
|
255
|
+
Object.assign(
|
|
256
|
+
attributes,
|
|
257
|
+
flattenToAttributes(structured.details, "error.details")
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
return attributes;
|
|
261
|
+
}
|
|
262
|
+
function recordStructuredError(ctx2, error) {
|
|
263
|
+
ctx2.recordException(error);
|
|
264
|
+
ctx2.setStatus({
|
|
265
|
+
code: api.SpanStatusCode.ERROR,
|
|
266
|
+
message: error.message
|
|
267
|
+
});
|
|
268
|
+
ctx2.setAttributes(getStructuredErrorAttributes(error));
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// src/request-logger.ts
|
|
272
|
+
function resolveContext(ctx2) {
|
|
273
|
+
if (ctx2) return ctx2;
|
|
274
|
+
const span2 = api.trace.getActiveSpan();
|
|
275
|
+
if (!span2) {
|
|
276
|
+
throw new Error(
|
|
277
|
+
"[autotel] getRequestLogger() requires an active span. Wrap your handler with trace()."
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
return chunkW4EUTSB2_cjs.createTraceContext(span2);
|
|
281
|
+
}
|
|
282
|
+
function getRequestLogger(ctx2, options) {
|
|
283
|
+
const activeContext = resolveContext(ctx2);
|
|
284
|
+
let contextState = {};
|
|
285
|
+
const addLogEvent = (level, message, fields) => {
|
|
286
|
+
const attrs2 = fields ? flattenToAttributes(fields) : void 0;
|
|
287
|
+
activeContext.addEvent(`log.${level}`, {
|
|
288
|
+
message,
|
|
289
|
+
...attrs2
|
|
290
|
+
});
|
|
291
|
+
};
|
|
292
|
+
return {
|
|
293
|
+
set(fields) {
|
|
294
|
+
contextState = {
|
|
295
|
+
...contextState,
|
|
296
|
+
...fields
|
|
297
|
+
};
|
|
298
|
+
activeContext.setAttributes(flattenToAttributes(fields));
|
|
299
|
+
},
|
|
300
|
+
info(message, fields) {
|
|
301
|
+
addLogEvent("info", message, fields);
|
|
302
|
+
if (fields) {
|
|
303
|
+
contextState = {
|
|
304
|
+
...contextState,
|
|
305
|
+
...fields
|
|
306
|
+
};
|
|
307
|
+
activeContext.setAttributes(flattenToAttributes(fields));
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
warn(message, fields) {
|
|
311
|
+
addLogEvent("warn", message, fields);
|
|
312
|
+
activeContext.setAttribute("autotel.log.level", "warn");
|
|
313
|
+
if (fields) {
|
|
314
|
+
contextState = {
|
|
315
|
+
...contextState,
|
|
316
|
+
...fields
|
|
317
|
+
};
|
|
318
|
+
activeContext.setAttributes(flattenToAttributes(fields));
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
error(error, fields) {
|
|
322
|
+
const err = typeof error === "string" ? new Error(error) : error;
|
|
323
|
+
recordStructuredError(activeContext, err);
|
|
324
|
+
addLogEvent("error", err.message, fields);
|
|
325
|
+
if (fields) {
|
|
326
|
+
contextState = {
|
|
327
|
+
...contextState,
|
|
328
|
+
...fields
|
|
329
|
+
};
|
|
330
|
+
activeContext.setAttributes(flattenToAttributes(fields));
|
|
331
|
+
}
|
|
332
|
+
activeContext.setAttribute("autotel.log.level", "error");
|
|
333
|
+
},
|
|
334
|
+
getContext() {
|
|
335
|
+
return { ...contextState };
|
|
336
|
+
},
|
|
337
|
+
emitNow(overrides) {
|
|
338
|
+
const mergedContext = {
|
|
339
|
+
...contextState,
|
|
340
|
+
...overrides ?? {}
|
|
341
|
+
};
|
|
342
|
+
const flattened = flattenToAttributes(mergedContext);
|
|
343
|
+
activeContext.setAttributes(flattened);
|
|
344
|
+
const snapshot = {
|
|
345
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
346
|
+
traceId: activeContext.traceId,
|
|
347
|
+
spanId: activeContext.spanId,
|
|
348
|
+
correlationId: activeContext.correlationId,
|
|
349
|
+
context: mergedContext
|
|
350
|
+
};
|
|
351
|
+
activeContext.addEvent("log.emit.manual", {
|
|
352
|
+
...flattened
|
|
353
|
+
});
|
|
354
|
+
if (options?.onEmit) {
|
|
355
|
+
Promise.resolve(options.onEmit(snapshot)).catch((error) => {
|
|
356
|
+
console.warn("[autotel] request logger onEmit failed:", error);
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
return snapshot;
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
Object.defineProperty(exports, "createDrainPipeline", {
|
|
365
|
+
enumerable: true,
|
|
366
|
+
get: function () { return chunk7EQ4G4SI_cjs.createDrainPipeline; }
|
|
367
|
+
});
|
|
167
368
|
Object.defineProperty(exports, "getCurrentWorkflowContext", {
|
|
168
369
|
enumerable: true,
|
|
169
|
-
get: function () { return
|
|
370
|
+
get: function () { return chunkBSZP4URK_cjs.getCurrentWorkflowContext; }
|
|
170
371
|
});
|
|
171
372
|
Object.defineProperty(exports, "isInWorkflow", {
|
|
172
373
|
enumerable: true,
|
|
173
|
-
get: function () { return
|
|
374
|
+
get: function () { return chunkBSZP4URK_cjs.isInWorkflow; }
|
|
174
375
|
});
|
|
175
376
|
Object.defineProperty(exports, "traceStep", {
|
|
176
377
|
enumerable: true,
|
|
177
|
-
get: function () { return
|
|
378
|
+
get: function () { return chunkBSZP4URK_cjs.traceStep; }
|
|
178
379
|
});
|
|
179
380
|
Object.defineProperty(exports, "traceWorkflow", {
|
|
180
381
|
enumerable: true,
|
|
181
|
-
get: function () { return
|
|
382
|
+
get: function () { return chunkBSZP4URK_cjs.traceWorkflow; }
|
|
182
383
|
});
|
|
183
384
|
Object.defineProperty(exports, "attrs", {
|
|
184
385
|
enumerable: true,
|
|
@@ -264,13 +465,17 @@ Object.defineProperty(exports, "URLAttributes", {
|
|
|
264
465
|
enumerable: true,
|
|
265
466
|
get: function () { return chunkESMHTKLJ_cjs.URLAttributes; }
|
|
266
467
|
});
|
|
468
|
+
Object.defineProperty(exports, "parseError", {
|
|
469
|
+
enumerable: true,
|
|
470
|
+
get: function () { return chunkT4B5LB6E_cjs.parseError; }
|
|
471
|
+
});
|
|
267
472
|
Object.defineProperty(exports, "traceConsumer", {
|
|
268
473
|
enumerable: true,
|
|
269
|
-
get: function () { return
|
|
474
|
+
get: function () { return chunk4RZ4JUBY_cjs.traceConsumer; }
|
|
270
475
|
});
|
|
271
476
|
Object.defineProperty(exports, "traceProducer", {
|
|
272
477
|
enumerable: true,
|
|
273
|
-
get: function () { return
|
|
478
|
+
get: function () { return chunk4RZ4JUBY_cjs.traceProducer; }
|
|
274
479
|
});
|
|
275
480
|
Object.defineProperty(exports, "BusinessBaggage", {
|
|
276
481
|
enumerable: true,
|
|
@@ -314,55 +519,55 @@ Object.defineProperty(exports, "getMeter", {
|
|
|
314
519
|
});
|
|
315
520
|
Object.defineProperty(exports, "traceDB", {
|
|
316
521
|
enumerable: true,
|
|
317
|
-
get: function () { return
|
|
522
|
+
get: function () { return chunkAXFWWJF3_cjs.traceDB; }
|
|
318
523
|
});
|
|
319
524
|
Object.defineProperty(exports, "traceHTTP", {
|
|
320
525
|
enumerable: true,
|
|
321
|
-
get: function () { return
|
|
526
|
+
get: function () { return chunkAXFWWJF3_cjs.traceHTTP; }
|
|
322
527
|
});
|
|
323
528
|
Object.defineProperty(exports, "traceLLM", {
|
|
324
529
|
enumerable: true,
|
|
325
|
-
get: function () { return
|
|
530
|
+
get: function () { return chunkAXFWWJF3_cjs.traceLLM; }
|
|
326
531
|
});
|
|
327
532
|
Object.defineProperty(exports, "traceMessaging", {
|
|
328
533
|
enumerable: true,
|
|
329
|
-
get: function () { return
|
|
534
|
+
get: function () { return chunkAXFWWJF3_cjs.traceMessaging; }
|
|
330
535
|
});
|
|
331
536
|
Object.defineProperty(exports, "ctx", {
|
|
332
537
|
enumerable: true,
|
|
333
|
-
get: function () { return
|
|
538
|
+
get: function () { return chunk3ZFDJJWZ_cjs.ctx; }
|
|
334
539
|
});
|
|
335
540
|
Object.defineProperty(exports, "getEventQueue", {
|
|
336
541
|
enumerable: true,
|
|
337
|
-
get: function () { return
|
|
542
|
+
get: function () { return chunk3ZFDJJWZ_cjs.getEventQueue; }
|
|
338
543
|
});
|
|
339
544
|
Object.defineProperty(exports, "instrument", {
|
|
340
545
|
enumerable: true,
|
|
341
|
-
get: function () { return
|
|
546
|
+
get: function () { return chunk3ZFDJJWZ_cjs.instrument; }
|
|
342
547
|
});
|
|
343
548
|
Object.defineProperty(exports, "span", {
|
|
344
549
|
enumerable: true,
|
|
345
|
-
get: function () { return
|
|
550
|
+
get: function () { return chunk3ZFDJJWZ_cjs.span; }
|
|
346
551
|
});
|
|
347
552
|
Object.defineProperty(exports, "trace", {
|
|
348
553
|
enumerable: true,
|
|
349
|
-
get: function () { return
|
|
554
|
+
get: function () { return chunk3ZFDJJWZ_cjs.trace; }
|
|
350
555
|
});
|
|
351
556
|
Object.defineProperty(exports, "track", {
|
|
352
557
|
enumerable: true,
|
|
353
|
-
get: function () { return
|
|
558
|
+
get: function () { return chunk3ZFDJJWZ_cjs.track; }
|
|
354
559
|
});
|
|
355
560
|
Object.defineProperty(exports, "withBaggage", {
|
|
356
561
|
enumerable: true,
|
|
357
|
-
get: function () { return
|
|
562
|
+
get: function () { return chunk3ZFDJJWZ_cjs.withBaggage; }
|
|
358
563
|
});
|
|
359
564
|
Object.defineProperty(exports, "withNewContext", {
|
|
360
565
|
enumerable: true,
|
|
361
|
-
get: function () { return
|
|
566
|
+
get: function () { return chunk3ZFDJJWZ_cjs.withNewContext; }
|
|
362
567
|
});
|
|
363
568
|
Object.defineProperty(exports, "withTracing", {
|
|
364
569
|
enumerable: true,
|
|
365
|
-
get: function () { return
|
|
570
|
+
get: function () { return chunk3ZFDJJWZ_cjs.withTracing; }
|
|
366
571
|
});
|
|
367
572
|
Object.defineProperty(exports, "defineBaggageSchema", {
|
|
368
573
|
enumerable: true,
|
|
@@ -414,15 +619,15 @@ Object.defineProperty(exports, "runWithSpan", {
|
|
|
414
619
|
});
|
|
415
620
|
Object.defineProperty(exports, "Event", {
|
|
416
621
|
enumerable: true,
|
|
417
|
-
get: function () { return
|
|
622
|
+
get: function () { return chunkMSUHW2I4_cjs.Event; }
|
|
418
623
|
});
|
|
419
624
|
Object.defineProperty(exports, "getEvents", {
|
|
420
625
|
enumerable: true,
|
|
421
|
-
get: function () { return
|
|
626
|
+
get: function () { return chunkMSUHW2I4_cjs.getEvents; }
|
|
422
627
|
});
|
|
423
628
|
Object.defineProperty(exports, "resetEvents", {
|
|
424
629
|
enumerable: true,
|
|
425
|
-
get: function () { return
|
|
630
|
+
get: function () { return chunkMSUHW2I4_cjs.resetEvents; }
|
|
426
631
|
});
|
|
427
632
|
Object.defineProperty(exports, "getOperationContext", {
|
|
428
633
|
enumerable: true,
|
|
@@ -462,11 +667,11 @@ Object.defineProperty(exports, "setCorrelationIdInBaggage", {
|
|
|
462
667
|
});
|
|
463
668
|
Object.defineProperty(exports, "BaggageSpanProcessor", {
|
|
464
669
|
enumerable: true,
|
|
465
|
-
get: function () { return
|
|
670
|
+
get: function () { return chunkHSEIUH7F_cjs.BaggageSpanProcessor; }
|
|
466
671
|
});
|
|
467
672
|
Object.defineProperty(exports, "init", {
|
|
468
673
|
enumerable: true,
|
|
469
|
-
get: function () { return
|
|
674
|
+
get: function () { return chunkHSEIUH7F_cjs.init; }
|
|
470
675
|
});
|
|
471
676
|
Object.defineProperty(exports, "FilteringSpanProcessor", {
|
|
472
677
|
enumerable: true,
|
|
@@ -500,6 +705,10 @@ Object.defineProperty(exports, "createRedactedSpan", {
|
|
|
500
705
|
enumerable: true,
|
|
501
706
|
get: function () { return chunkELW34S4C_cjs.createRedactedSpan; }
|
|
502
707
|
});
|
|
708
|
+
Object.defineProperty(exports, "formatDuration", {
|
|
709
|
+
enumerable: true,
|
|
710
|
+
get: function () { return chunk6S5RUKU3_cjs.formatDuration; }
|
|
711
|
+
});
|
|
503
712
|
Object.defineProperty(exports, "AdaptiveSampler", {
|
|
504
713
|
enumerable: true,
|
|
505
714
|
get: function () { return chunkBGVKKL2N_cjs.AdaptiveSampler; }
|
|
@@ -564,7 +773,13 @@ Object.defineProperty(exports, "propagation", {
|
|
|
564
773
|
enumerable: true,
|
|
565
774
|
get: function () { return api.propagation; }
|
|
566
775
|
});
|
|
776
|
+
exports.createStructuredError = createStructuredError;
|
|
777
|
+
exports.flattenToAttributes = flattenToAttributes;
|
|
567
778
|
exports.flush = flush;
|
|
779
|
+
exports.getRequestLogger = getRequestLogger;
|
|
780
|
+
exports.getStructuredErrorAttributes = getStructuredErrorAttributes;
|
|
781
|
+
exports.recordStructuredError = recordStructuredError;
|
|
568
782
|
exports.shutdown = shutdown;
|
|
783
|
+
exports.toAttributeValue = toAttributeValue;
|
|
569
784
|
//# sourceMappingURL=index.cjs.map
|
|
570
785
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shutdown.ts"],"names":["getEventQueue","getSdk","getLogger","resetEvents","resetMetrics","resetEventQueue"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,eAAsB,MAAM,OAAA,EAGV;AAChB,EAAA,MAAM,OAAA,GAAU,SAAS,OAAA,IAAW,GAAA;AACpC,EAAA,MAAM,WAAA,GAAc,SAAS,WAAA,IAAe,KAAA;AAE5C,EAAA,MAAM,UAAU,YAAY;AAE1B,IAAA,MAAM,cAAcA,+BAAA,EAAc;AAClC,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,MAAM,YAAY,QAAA,EAAS;AAAA,MAC7B,CAAA,MAAO;AACL,QAAA,MAAM,YAAY,KAAA,EAAM;AAAA,MAC1B;AAAA,IACF;AAIA,IAAA,MAAM,MAAMC,wBAAA,EAAO;AACnB,IAAA,IAAI,GAAA,EAAK;AACP,MAAA,IAAI;AAGF,QAAA,MAAM,MAAA,GAAS,GAAA;AACf,QAAA,IAAI,OAAO,MAAA,CAAO,iBAAA,KAAsB,UAAA,EAAY;AAClD,UAAA,MAAM,cAAA,GAAiB,OAAO,iBAAA,EAAkB;AAChD,UAAA,IACE,cAAA,IACA,OAAO,cAAA,CAAe,UAAA,KAAe,UAAA,EACrC;AACA,YAAA,MAAM,eAAe,UAAA,EAAW;AAAA,UAClC;AAAA,QACF;AAAA,MACF,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF,CAAA;AAGA,EAAA,IAAI,aAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAM,QAAQ,IAAA,CAAK;AAAA,MACjB,OAAA,EAAQ,CAAE,OAAA,CAAQ,MAAM;AAEtB,QAAA,IAAI,aAAA,EAAe;AACjB,UAAA,YAAA,CAAa,aAAa,CAAA;AAAA,QAC5B;AAAA,MACF,CAAC,CAAA;AAAA,MACD,IAAI,OAAA,CAAc,CAAC,CAAA,EAAG,MAAA,KAAW;AAC/B,QAAA,aAAA,GAAgB,UAAA;AAAA,UACd,MAAM,MAAA,CAAO,IAAI,KAAA,CAAM,eAAe,CAAC,CAAA;AAAA,UACvC;AAAA,SACF;AAGA,QAAA,aAAA,CAAc,KAAA,EAAM;AAAA,MACtB,CAAC;AAAA,KACF,CAAA;AAAA,EACH,SAAS,KAAA,EAAO;AAEd,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,YAAA,CAAa,aAAa,CAAA;AAAA,IAC5B;AACA,IAAA,MAAM,SAASC,2BAAA,EAAU;AACzB,IAAA,MAAA,CAAO,KAAA;AAAA,MACL;AAAA,QACE,GAAA,EAAK,iBAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC;AAAA,OAC/D;AAAA,MACA;AAAA,KACF;AACA,IAAA,MAAM,KAAA;AAAA,EACR;AACF;AAyBA,eAAsB,QAAA,GAA0B;AAC9C,EAAA,MAAM,SAASA,2BAAA,EAAU;AACzB,EAAA,IAAI,aAAA,GAA8B,IAAA;AAGlC,EAAA,IAAI;AACF,IAAA,MAAM,KAAA,CAAM,EAAE,WAAA,EAAa,IAAA,EAAM,CAAA;AAAA,EACnC,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,GAAA,GAAM,iBAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AACpE,IAAA,aAAA,GAAgB,GAAA;AAChB,IAAA,MAAA,CAAO,KAAA;AAAA,MACL;AAAA,QACE;AAAA,OACF;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAGA,EAAA,IAAI;AAEF,IAAA,MAAM,MAAMD,wBAAA,EAAO;AACnB,IAAA,IAAI,GAAA,EAAK;AACP,MAAA,MAAM,IAAI,QAAA,EAAS;AAAA,IACrB;AAAA,EACF,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,GAAA,GAAM,iBAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AAIpE,IAAA,MAAM,mBAAA,GACJ,OAAO,KAAA,KAAU,QAAA,IACjB,UAAU,IAAA,IACV,MAAA,IAAU,KAAA,IACV,KAAA,CAAM,IAAA,KAAS,cAAA;AAEjB,IAAA,IAAI,CAAC,mBAAA,EAAqB;AAExB,MAAA,IAAI,CAAC,aAAA,EAAe;AAClB,QAAA,aAAA,GAAgB,GAAA;AAAA,MAClB;AACA,MAAA,MAAA,CAAO,KAAA,CAAM,EAAE,GAAA,EAAI,EAAG,+BAA+B,CAAA;AAAA,IACvD;AAAA,EACF,CAAA,SAAE;AAGA,IAAA,MAAM,cAAcD,+BAAA,EAAc;AAClC,IAAA,IAAI,WAAA,IAAe,OAAO,WAAA,CAAY,OAAA,KAAY,UAAA,EAAY;AAC5D,MAAA,WAAA,CAAY,OAAA,EAAQ;AAAA,IACtB;AACA,IAAAG,6BAAA,EAAY;AACZ,IAAAC,8BAAA,EAAa;AACb,IAAAC,iCAAA,EAAgB;AAAA,EAClB;AAIA,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,MAAM,aAAA;AAAA,EACR;AACF;AAWA,SAAS,qBAAA,GAA8B;AACrC,EAAA,IAAI,OAAO,YAAY,WAAA,EAAa;AAEpC,EAAA,MAAM,OAAA,GAA4B,CAAC,SAAA,EAAW,QAAQ,CAAA;AACtD,EAAA,IAAI,YAAA,GAAe,KAAA;AAEnB,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,OAAA,CAAQ,EAAA,CAAG,QAAQ,YAAY;AAC7B,MAAA,IAAI,YAAA,EAAc;AAClB,MAAA,YAAA,GAAe,IAAA;AAEf,MAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,MAAA,EAAQ;AACnC,QAAAH,2BAAA,EAAU,CAAE,IAAA;AAAA,UACV,EAAC;AAAA,UACD,sBAAsB,MAAM,CAAA,uBAAA;AAAA,SAC9B;AAAA,MACF;AAEA,MAAA,IAAI;AACF,QAAA,MAAM,QAAA,EAAS;AAAA,MACjB,SAAS,KAAA,EAAO;AACd,QAAAA,2BAAA,EAAU,CAAE,KAAA;AAAA,UACV;AAAA,YACE,GAAA,EAAK,KAAA,YAAiB,KAAA,GAAQ,KAAA,GAAQ;AAAA,WACxC;AAAA,UACA;AAAA,SACF;AAAA,MACF,CAAA,SAAE;AACA,QAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,MAChB;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AACF;AAGA,qBAAA,EAAsB","file":"index.cjs","sourcesContent":["/**\n * Graceful shutdown with flush and cleanup\n */\n\nimport { getSdk, getLogger } from './init';\nimport { getEventQueue, resetEventQueue } from './track';\nimport { resetEvents } from './event';\nimport { resetMetrics } from './metric';\n\n/**\n * Flush all pending telemetry\n *\n * Flushes both events events and OpenTelemetry spans to their destinations.\n * Includes timeout protection to prevent hanging in serverless environments.\n *\n * Safe to call multiple times.\n *\n * @param options - Optional configuration\n * @param options.timeout - Timeout in milliseconds (default: 2000ms)\n * @param options.forShutdown - If true, permanently disables the events queue after flush (used internally by shutdown())\n *\n * @example Manual flush in serverless\n * ```typescript\n * import { flush } from 'autotel';\n *\n * export const handler = async (event) => {\n * // ... process event\n * await flush(); // Flush before function returns\n * return result;\n * };\n * ```\n *\n * @example With custom timeout\n * ```typescript\n * await flush({ timeout: 5000 }); // 5 second timeout\n * ```\n */\nexport async function flush(options?: {\n timeout?: number;\n forShutdown?: boolean;\n}): Promise<void> {\n const timeout = options?.timeout ?? 2000;\n const forShutdown = options?.forShutdown ?? false;\n\n const doFlush = async () => {\n // Flush events queue (or shutdown queue when tearing down)\n const eventsQueue = getEventQueue();\n if (eventsQueue) {\n if (forShutdown) {\n await eventsQueue.shutdown();\n } else {\n await eventsQueue.flush();\n }\n }\n\n // Flush OpenTelemetry spans\n // This ensures spans are exported immediately, critical for serverless\n const sdk = getSdk();\n if (sdk) {\n try {\n // Type assertion needed as getTracerProvider is not in the public NodeSDK interface\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sdkAny = sdk as any;\n if (typeof sdkAny.getTracerProvider === 'function') {\n const tracerProvider = sdkAny.getTracerProvider();\n if (\n tracerProvider &&\n typeof tracerProvider.forceFlush === 'function'\n ) {\n await tracerProvider.forceFlush();\n }\n }\n } catch {\n // Ignore errors when accessing tracer provider (may not be available in test mocks)\n }\n }\n };\n\n // Add timeout protection to prevent hanging\n let timeoutHandle: NodeJS.Timeout | undefined;\n try {\n await Promise.race([\n doFlush().finally(() => {\n // Clear timeout as soon as flush completes\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n }),\n new Promise<void>((_, reject) => {\n timeoutHandle = setTimeout(\n () => reject(new Error('Flush timeout')),\n timeout,\n );\n // Use unref() to allow Node to exit if flush completes first\n // This prevents the 2s delay in serverless when flush succeeds immediately\n timeoutHandle.unref();\n }),\n ]);\n } catch (error) {\n // Clear timeout on error too\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n const logger = getLogger();\n logger.error(\n {\n err: error instanceof Error ? error : new Error(String(error)),\n },\n '[autotel] Flush error',\n );\n throw error;\n }\n}\n\n/**\n * Shutdown telemetry and cleanup resources\n *\n * - Flushes all pending data\n * - Shuts down OpenTelemetry SDK\n * - Cleans up resources\n *\n * Call this before process exit.\n *\n * Always performs cleanup even if flush fails, preventing resource leaks\n * in serverless handlers or tests.\n *\n * @example Express server\n * ```typescript\n * const server = app.listen(3000)\n *\n * process.on('SIGTERM', async () => {\n * await server.close()\n * await shutdown()\n * process.exit(0)\n * })\n * ```\n */\nexport async function shutdown(): Promise<void> {\n const logger = getLogger();\n let shutdownError: Error | null = null;\n\n // Attempt to flush (with queue shutdown so new events are rejected), but continue with cleanup even if it fails\n try {\n await flush({ forShutdown: true });\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n shutdownError = err;\n logger.error(\n {\n err,\n },\n '[autotel] Flush failed during shutdown, continuing cleanup',\n );\n }\n\n // Always shutdown SDK and clean up resources\n try {\n // Shutdown OpenTelemetry SDK\n const sdk = getSdk();\n if (sdk) {\n await sdk.shutdown();\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n\n // Ignore ECONNREFUSED errors - this happens when no OTLP endpoint was configured\n // The SDK tries to flush exporters that don't exist, which is harmless\n const isConnectionRefused =\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n error.code === 'ECONNREFUSED';\n\n if (!isConnectionRefused) {\n // Only store/log non-connection errors\n if (!shutdownError) {\n shutdownError = err;\n }\n logger.error({ err }, '[autotel] SDK shutdown failed');\n }\n } finally {\n // Clean up singleton Maps and queues to prevent memory leaks\n // This runs even if SDK shutdown fails\n const eventsQueue = getEventQueue();\n if (eventsQueue && typeof eventsQueue.cleanup === 'function') {\n eventsQueue.cleanup();\n }\n resetEvents();\n resetMetrics();\n resetEventQueue();\n }\n\n // Rethrow first error after cleanup completes\n // This allows tests and CI to detect failures while still ensuring cleanup\n if (shutdownError) {\n throw shutdownError;\n }\n}\n\n/**\n * Register automatic shutdown hooks for common signals\n *\n * Handles:\n * - SIGTERM (Docker/K8s graceful shutdown)\n * - SIGINT (Ctrl+C)\n *\n * @internal Called automatically on module load\n */\nfunction registerShutdownHooks(): void {\n if (typeof process === 'undefined') return; // Not in Node.js\n\n const signals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT'];\n let shuttingDown = false;\n\n for (const signal of signals) {\n process.on(signal, async () => {\n if (shuttingDown) return; // Prevent double shutdown\n shuttingDown = true;\n\n if (process.env.NODE_ENV !== 'test') {\n getLogger().info(\n {},\n `[autotel] Received ${signal}, flushing telemetry...`,\n );\n }\n\n try {\n await shutdown();\n } catch (error) {\n getLogger().error(\n {\n err: error instanceof Error ? error : undefined,\n },\n '[autotel] Error during shutdown',\n );\n } finally {\n process.exit(0);\n }\n });\n }\n}\n\n// Auto-register shutdown hooks\nregisterShutdownHooks();\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/shutdown.ts","../src/flatten-attributes.ts","../src/structured-error.ts","../src/request-logger.ts"],"names":["getEventQueue","getSdk","getLogger","resetEvents","resetMetrics","resetEventQueue","ctx","SpanStatusCode","span","otelTrace","createTraceContext","attrs"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Graceful shutdown with flush and cleanup\n */\n\nimport { getSdk, getLogger } from './init';\nimport { getEventQueue, resetEventQueue } from './track';\nimport { resetEvents } from './event';\nimport { resetMetrics } from './metric';\n\n/**\n * Flush all pending telemetry\n *\n * Flushes both events events and OpenTelemetry spans to their destinations.\n * Includes timeout protection to prevent hanging in serverless environments.\n *\n * Safe to call multiple times.\n *\n * @param options - Optional configuration\n * @param options.timeout - Timeout in milliseconds (default: 2000ms)\n * @param options.forShutdown - If true, permanently disables the events queue after flush (used internally by shutdown())\n *\n * @example Manual flush in serverless\n * ```typescript\n * import { flush } from 'autotel';\n *\n * export const handler = async (event) => {\n * // ... process event\n * await flush(); // Flush before function returns\n * return result;\n * };\n * ```\n *\n * @example With custom timeout\n * ```typescript\n * await flush({ timeout: 5000 }); // 5 second timeout\n * ```\n */\nexport async function flush(options?: {\n timeout?: number;\n forShutdown?: boolean;\n}): Promise<void> {\n const timeout = options?.timeout ?? 2000;\n const forShutdown = options?.forShutdown ?? false;\n\n const doFlush = async () => {\n // Flush events queue (or shutdown queue when tearing down)\n const eventsQueue = getEventQueue();\n if (eventsQueue) {\n if (forShutdown) {\n await eventsQueue.shutdown();\n } else {\n await eventsQueue.flush();\n }\n }\n\n // Flush OpenTelemetry spans\n // This ensures spans are exported immediately, critical for serverless\n const sdk = getSdk();\n if (sdk) {\n try {\n // Type assertion needed as getTracerProvider is not in the public NodeSDK interface\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sdkAny = sdk as any;\n if (typeof sdkAny.getTracerProvider === 'function') {\n const tracerProvider = sdkAny.getTracerProvider();\n if (\n tracerProvider &&\n typeof tracerProvider.forceFlush === 'function'\n ) {\n await tracerProvider.forceFlush();\n }\n }\n } catch {\n // Ignore errors when accessing tracer provider (may not be available in test mocks)\n }\n }\n };\n\n // Add timeout protection to prevent hanging\n let timeoutHandle: NodeJS.Timeout | undefined;\n try {\n await Promise.race([\n doFlush().finally(() => {\n // Clear timeout as soon as flush completes\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n }),\n new Promise<void>((_, reject) => {\n timeoutHandle = setTimeout(\n () => reject(new Error('Flush timeout')),\n timeout,\n );\n // Use unref() to allow Node to exit if flush completes first\n // This prevents the 2s delay in serverless when flush succeeds immediately\n timeoutHandle.unref();\n }),\n ]);\n } catch (error) {\n // Clear timeout on error too\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n const logger = getLogger();\n logger.error(\n {\n err: error instanceof Error ? error : new Error(String(error)),\n },\n '[autotel] Flush error',\n );\n throw error;\n }\n}\n\n/**\n * Shutdown telemetry and cleanup resources\n *\n * - Flushes all pending data\n * - Shuts down OpenTelemetry SDK\n * - Cleans up resources\n *\n * Call this before process exit.\n *\n * Always performs cleanup even if flush fails, preventing resource leaks\n * in serverless handlers or tests.\n *\n * @example Express server\n * ```typescript\n * const server = app.listen(3000)\n *\n * process.on('SIGTERM', async () => {\n * await server.close()\n * await shutdown()\n * process.exit(0)\n * })\n * ```\n */\nexport async function shutdown(): Promise<void> {\n const logger = getLogger();\n let shutdownError: Error | null = null;\n\n // Attempt to flush (with queue shutdown so new events are rejected), but continue with cleanup even if it fails\n try {\n await flush({ forShutdown: true });\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n shutdownError = err;\n logger.error(\n {\n err,\n },\n '[autotel] Flush failed during shutdown, continuing cleanup',\n );\n }\n\n // Always shutdown SDK and clean up resources\n try {\n // Shutdown OpenTelemetry SDK\n const sdk = getSdk();\n if (sdk) {\n await sdk.shutdown();\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n\n // Ignore ECONNREFUSED errors - this happens when no OTLP endpoint was configured\n // The SDK tries to flush exporters that don't exist, which is harmless\n const isConnectionRefused =\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n error.code === 'ECONNREFUSED';\n\n if (!isConnectionRefused) {\n // Only store/log non-connection errors\n if (!shutdownError) {\n shutdownError = err;\n }\n logger.error({ err }, '[autotel] SDK shutdown failed');\n }\n } finally {\n // Clean up singleton Maps and queues to prevent memory leaks\n // This runs even if SDK shutdown fails\n const eventsQueue = getEventQueue();\n if (eventsQueue && typeof eventsQueue.cleanup === 'function') {\n eventsQueue.cleanup();\n }\n resetEvents();\n resetMetrics();\n resetEventQueue();\n }\n\n // Rethrow first error after cleanup completes\n // This allows tests and CI to detect failures while still ensuring cleanup\n if (shutdownError) {\n throw shutdownError;\n }\n}\n\n/**\n * Register automatic shutdown hooks for common signals\n *\n * Handles:\n * - SIGTERM (Docker/K8s graceful shutdown)\n * - SIGINT (Ctrl+C)\n *\n * @internal Called automatically on module load\n */\nfunction registerShutdownHooks(): void {\n if (typeof process === 'undefined') return; // Not in Node.js\n\n const signals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT'];\n let shuttingDown = false;\n\n for (const signal of signals) {\n process.on(signal, async () => {\n if (shuttingDown) return; // Prevent double shutdown\n shuttingDown = true;\n\n if (process.env.NODE_ENV !== 'test') {\n getLogger().info(\n {},\n `[autotel] Received ${signal}, flushing telemetry...`,\n );\n }\n\n try {\n await shutdown();\n } catch (error) {\n getLogger().error(\n {\n err: error instanceof Error ? error : undefined,\n },\n '[autotel] Error during shutdown',\n );\n } finally {\n process.exit(0);\n }\n });\n }\n}\n\n// Auto-register shutdown hooks\nregisterShutdownHooks();\n","import type { AttributeValue } from './trace-context';\n\n/**\n * Convert an unknown value to an OTel-compatible AttributeValue.\n * Returns undefined when the value cannot be represented.\n */\nexport function toAttributeValue(value: unknown): AttributeValue | undefined {\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n return value;\n }\n if (Array.isArray(value)) {\n if (\n value.every((v) => typeof v === 'string') ||\n value.every((v) => typeof v === 'number') ||\n value.every((v) => typeof v === 'boolean')\n ) {\n return value as AttributeValue;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return '<serialization-failed>';\n }\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (value instanceof Error) {\n return value.message;\n }\n return undefined;\n}\n\n/**\n * Recursively flatten a nested object into dot-notation OTel attributes.\n * Includes circular reference protection via WeakSet.\n */\nexport function flattenToAttributes(\n fields: Record<string, unknown>,\n prefix = '',\n): Record<string, AttributeValue> {\n const out: Record<string, AttributeValue> = {};\n const seen = new WeakSet<object>();\n\n function flatten(obj: Record<string, unknown>, currentPrefix: string): void {\n for (const [key, value] of Object.entries(obj)) {\n if (value == null) continue;\n const nextKey = currentPrefix ? `${currentPrefix}.${key}` : key;\n\n const attr = toAttributeValue(value);\n if (attr !== undefined) {\n out[nextKey] = attr;\n continue;\n }\n\n if (typeof value === 'object' && value.constructor === Object) {\n if (seen.has(value)) {\n out[nextKey] = '<circular-reference>';\n continue;\n }\n seen.add(value);\n flatten(value as Record<string, unknown>, nextKey);\n continue;\n }\n\n try {\n out[nextKey] = JSON.stringify(value);\n } catch {\n out[nextKey] = '<serialization-failed>';\n }\n }\n }\n\n flatten(fields, prefix);\n return out;\n}\n","import { SpanStatusCode } from '@opentelemetry/api';\nimport type { AttributeValue, TraceContext } from './trace-context';\nimport { flattenToAttributes } from './flatten-attributes';\n\nexport interface StructuredErrorInput {\n message: string;\n why?: string;\n fix?: string;\n link?: string;\n code?: string | number;\n status?: number;\n cause?: unknown;\n details?: Record<string, unknown>;\n name?: string;\n}\n\nexport interface StructuredError extends Error {\n why?: string;\n fix?: string;\n link?: string;\n code?: string | number;\n status?: number;\n details?: Record<string, unknown>;\n}\n\nexport function createStructuredError(\n input: StructuredErrorInput,\n): StructuredError {\n const error = new Error(input.message, {\n cause: input.cause,\n }) as StructuredError;\n\n error.name = input.name ?? 'StructuredError';\n if (input.why !== undefined) error.why = input.why;\n if (input.fix !== undefined) error.fix = input.fix;\n if (input.link !== undefined) error.link = input.link;\n if (input.code !== undefined) error.code = input.code;\n if (input.status !== undefined) error.status = input.status;\n if (input.details !== undefined) error.details = input.details;\n\n return error;\n}\n\nexport function getStructuredErrorAttributes(\n error: Error,\n): Record<string, AttributeValue> {\n const structured = error as StructuredError;\n const attributes: Record<string, AttributeValue> = {\n 'error.type': error.name || 'Error',\n 'error.message': error.message,\n };\n\n if (error.stack) attributes['error.stack'] = error.stack;\n if (structured.why) attributes['error.why'] = structured.why;\n if (structured.fix) attributes['error.fix'] = structured.fix;\n if (structured.link) attributes['error.link'] = structured.link;\n if (structured.code !== undefined) {\n attributes['error.code'] =\n typeof structured.code === 'string'\n ? structured.code\n : String(structured.code);\n }\n if (structured.status !== undefined) {\n attributes['error.status'] = structured.status;\n }\n if (structured.details) {\n Object.assign(\n attributes,\n flattenToAttributes(structured.details, 'error.details'),\n );\n }\n\n return attributes;\n}\n\nexport function recordStructuredError(\n ctx: Pick<TraceContext, 'recordException' | 'setAttributes' | 'setStatus'>,\n error: Error,\n): void {\n ctx.recordException(error);\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: error.message,\n });\n ctx.setAttributes(getStructuredErrorAttributes(error));\n}\n","import { trace as otelTrace } from '@opentelemetry/api';\nimport type { TraceContext } from './trace-context';\nimport { createTraceContext } from './trace-context';\nimport { recordStructuredError } from './structured-error';\nimport { flattenToAttributes } from './flatten-attributes';\n\nexport interface RequestLogger {\n set(fields: Record<string, unknown>): void;\n info(message: string, fields?: Record<string, unknown>): void;\n warn(message: string, fields?: Record<string, unknown>): void;\n error(error: Error | string, fields?: Record<string, unknown>): void;\n getContext(): Record<string, unknown>;\n emitNow(overrides?: Record<string, unknown>): RequestLogSnapshot;\n}\n\nexport interface RequestLogSnapshot {\n timestamp: string;\n traceId: string;\n spanId: string;\n correlationId: string;\n context: Record<string, unknown>;\n}\n\nexport interface RequestLoggerOptions {\n /** Callback invoked by emitNow() for manual fan-out. */\n onEmit?: (snapshot: RequestLogSnapshot) => void | Promise<void>;\n}\n\nfunction resolveContext(ctx?: TraceContext): TraceContext {\n if (ctx) return ctx;\n\n const span = otelTrace.getActiveSpan();\n if (!span) {\n throw new Error(\n '[autotel] getRequestLogger() requires an active span. Wrap your handler with trace().',\n );\n }\n return createTraceContext(span);\n}\n\nexport function getRequestLogger(\n ctx?: TraceContext,\n options?: RequestLoggerOptions,\n): RequestLogger {\n const activeContext = resolveContext(ctx);\n let contextState: Record<string, unknown> = {};\n\n const addLogEvent = (\n level: 'info' | 'warn' | 'error',\n message: string,\n fields?: Record<string, unknown>,\n ) => {\n const attrs = fields ? flattenToAttributes(fields) : undefined;\n activeContext.addEvent(`log.${level}`, {\n message,\n ...attrs,\n });\n };\n\n return {\n set(fields: Record<string, unknown>) {\n contextState = {\n ...contextState,\n ...fields,\n };\n activeContext.setAttributes(flattenToAttributes(fields));\n },\n\n info(message: string, fields?: Record<string, unknown>) {\n addLogEvent('info', message, fields);\n if (fields) {\n contextState = {\n ...contextState,\n ...fields,\n };\n activeContext.setAttributes(flattenToAttributes(fields));\n }\n },\n\n warn(message: string, fields?: Record<string, unknown>) {\n addLogEvent('warn', message, fields);\n activeContext.setAttribute('autotel.log.level', 'warn');\n if (fields) {\n contextState = {\n ...contextState,\n ...fields,\n };\n activeContext.setAttributes(flattenToAttributes(fields));\n }\n },\n\n error(error: Error | string, fields?: Record<string, unknown>) {\n const err = typeof error === 'string' ? new Error(error) : error;\n recordStructuredError(activeContext, err);\n addLogEvent('error', err.message, fields);\n\n if (fields) {\n contextState = {\n ...contextState,\n ...fields,\n };\n activeContext.setAttributes(flattenToAttributes(fields));\n }\n activeContext.setAttribute('autotel.log.level', 'error');\n },\n\n getContext() {\n return { ...contextState };\n },\n\n emitNow(overrides?: Record<string, unknown>): RequestLogSnapshot {\n const mergedContext = {\n ...contextState,\n ...(overrides ?? {}),\n };\n const flattened = flattenToAttributes(mergedContext);\n activeContext.setAttributes(flattened);\n\n const snapshot: RequestLogSnapshot = {\n timestamp: new Date().toISOString(),\n traceId: activeContext.traceId,\n spanId: activeContext.spanId,\n correlationId: activeContext.correlationId,\n context: mergedContext,\n };\n\n activeContext.addEvent('log.emit.manual', {\n ...flattened,\n });\n\n if (options?.onEmit) {\n Promise.resolve(options.onEmit(snapshot)).catch((error) => {\n console.warn('[autotel] request logger onEmit failed:', error);\n });\n }\n\n return snapshot;\n },\n };\n}\n"]}
|