@elysia/opentelemetry 1.4.11

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.
@@ -0,0 +1,70 @@
1
+ import { Elysia } from 'elysia';
2
+ import { type ContextManager, type Context, type SpanOptions, type Span, type Attributes, TraceAPI, TracerProvider } from '@opentelemetry/api';
3
+ import { NodeSDK } from '@opentelemetry/sdk-node';
4
+ type OpenTeleMetryOptions = NonNullable<ConstructorParameters<typeof NodeSDK>[0]>;
5
+ /**
6
+ * Initialize OpenTelemetry SDK
7
+ *
8
+ * For best practice, you should be using preload OpenTelemetry SDK if possible
9
+ * however, this is a simple way to initialize OpenTelemetry SDK
10
+ */
11
+ export interface ElysiaOpenTelemetryOptions extends OpenTeleMetryOptions {
12
+ contextManager?: ContextManager;
13
+ /**
14
+ * Optional function to determine whether a given request should be traced.
15
+ *
16
+ * @param req - The incoming request object to evaluate.
17
+ * @returns A boolean indicating whether tracing should be enabled for this request.
18
+ */
19
+ checkIfShouldTrace?: (req: Request) => boolean;
20
+ }
21
+ export type ActiveSpanArgs<F extends (span: Span) => unknown = (span: Span) => unknown> = [name: string, fn: F] | [name: string, options: SpanOptions, fn: F] | [name: string, options: SpanOptions, context: Context, fn: F];
22
+ export declare const shouldStartNodeSDK: (provider: TracerProvider) => boolean;
23
+ export type Tracer = ReturnType<TraceAPI['getTracer']>;
24
+ export type StartSpan = Tracer['startSpan'];
25
+ export type StartActiveSpan = Tracer['startActiveSpan'];
26
+ export declare const contextKeySpan: unique symbol;
27
+ export declare const getTracer: () => ReturnType<TraceAPI["getTracer"]>;
28
+ export declare const startSpan: (name: string, options?: SpanOptions, context?: Context) => Span;
29
+ export declare const startActiveSpan: StartActiveSpan;
30
+ export declare const record: {
31
+ <F extends (span: Span) => unknown>(name: string, fn: F): ReturnType<F>;
32
+ <F extends (span: Span) => unknown>(name: string, options: SpanOptions, fn: F): ReturnType<F>;
33
+ <F extends (span: Span) => unknown>(name: string, options: SpanOptions, context: Context, fn: F): ReturnType<F>;
34
+ };
35
+ export declare const getCurrentSpan: () => Span | undefined;
36
+ /**
37
+ * Set attributes to the current span
38
+ *
39
+ * @returns boolean - whether the attributes are set or not
40
+ */
41
+ export declare const setAttributes: (attributes: Attributes) => boolean;
42
+ export declare const opentelemetry: ({ serviceName, instrumentations, contextManager, checkIfShouldTrace, ...options }?: ElysiaOpenTelemetryOptions) => Elysia<"", {
43
+ decorator: {};
44
+ store: {};
45
+ derive: {};
46
+ resolve: {};
47
+ }, {
48
+ typebox: {};
49
+ error: {};
50
+ }, {
51
+ schema: {};
52
+ standaloneSchema: {};
53
+ macro: {};
54
+ macroFn: {};
55
+ parser: {};
56
+ response: {};
57
+ }, {}, {
58
+ derive: {};
59
+ resolve: {};
60
+ schema: {};
61
+ standaloneSchema: {};
62
+ response: {};
63
+ }, {
64
+ derive: {};
65
+ resolve: {};
66
+ schema: {};
67
+ standaloneSchema: {};
68
+ response: {};
69
+ }>;
70
+ export {};
@@ -0,0 +1,632 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ contextKeySpan: () => contextKeySpan,
24
+ getCurrentSpan: () => getCurrentSpan,
25
+ getTracer: () => getTracer,
26
+ opentelemetry: () => opentelemetry,
27
+ record: () => record,
28
+ setAttributes: () => setAttributes,
29
+ shouldStartNodeSDK: () => shouldStartNodeSDK,
30
+ startActiveSpan: () => startActiveSpan,
31
+ startSpan: () => startSpan
32
+ });
33
+ module.exports = __toCommonJS(index_exports);
34
+ var import_elysia = require("elysia");
35
+ var import_api = require("@opentelemetry/api");
36
+ var import_sdk_node = require("@opentelemetry/sdk-node");
37
+ var headerHasToJSON = typeof new Headers().toJSON === "function";
38
+ var parseNumericString = (message) => {
39
+ if (message.length < 16) {
40
+ if (message.length === 0) return null;
41
+ const length = Number(message);
42
+ if (Number.isNaN(length)) return null;
43
+ return length;
44
+ }
45
+ if (message.length === 16) {
46
+ const number = Number(message);
47
+ if (number.toString() !== message || message.trim().length === 0 || Number.isNaN(number))
48
+ return null;
49
+ return number;
50
+ }
51
+ return null;
52
+ };
53
+ var createActiveSpanHandler = (fn) => function(span) {
54
+ try {
55
+ const result = fn(span);
56
+ if (result instanceof Promise || typeof result?.then === "function")
57
+ return Promise.resolve(result).then(
58
+ (value) => {
59
+ span.end();
60
+ return value;
61
+ },
62
+ (rejectResult) => {
63
+ span.setStatus({
64
+ code: import_api.SpanStatusCode.ERROR,
65
+ message: rejectResult instanceof Error ? rejectResult.message : JSON.stringify(
66
+ rejectResult ?? "Unknown error"
67
+ )
68
+ });
69
+ span.recordException(rejectResult);
70
+ span.end();
71
+ throw rejectResult;
72
+ }
73
+ );
74
+ span.end();
75
+ return result;
76
+ } catch (error) {
77
+ const err = error;
78
+ span.setStatus({
79
+ code: import_api.SpanStatusCode.ERROR,
80
+ message: err?.message
81
+ });
82
+ span.recordException(err);
83
+ span.end();
84
+ throw error;
85
+ }
86
+ };
87
+ var createContext = (parent) => ({
88
+ getValue() {
89
+ return parent;
90
+ },
91
+ setValue() {
92
+ return import_api.context.active();
93
+ },
94
+ deleteValue() {
95
+ return import_api.context.active();
96
+ }
97
+ });
98
+ var shouldStartNodeSDK = (provider) => {
99
+ return provider instanceof import_api.ProxyTracerProvider && provider.getDelegateTracer("check") === void 0;
100
+ };
101
+ var contextKeySpan = Symbol.for("OpenTelemetry Context Key SPAN");
102
+ var getTracer = () => {
103
+ const tracer = import_api.trace.getTracer("Elysia");
104
+ return {
105
+ ...tracer,
106
+ startSpan(name, options, context) {
107
+ return tracer.startSpan(name, options, context);
108
+ },
109
+ startActiveSpan(...args) {
110
+ switch (args.length) {
111
+ case 2:
112
+ return tracer.startActiveSpan(
113
+ args[0],
114
+ createActiveSpanHandler(args[1])
115
+ );
116
+ case 3:
117
+ return tracer.startActiveSpan(
118
+ args[0],
119
+ args[1],
120
+ createActiveSpanHandler(args[2])
121
+ );
122
+ case 4:
123
+ return tracer.startActiveSpan(
124
+ args[0],
125
+ args[1],
126
+ args[2],
127
+ createActiveSpanHandler(args[3])
128
+ );
129
+ }
130
+ }
131
+ };
132
+ };
133
+ var startSpan = (name, options, context) => {
134
+ const tracer = getTracer();
135
+ return tracer.startSpan(name, options, context);
136
+ };
137
+ var startActiveSpan = (...args) => {
138
+ const tracer = getTracer();
139
+ switch (args.length) {
140
+ case 2:
141
+ return tracer.startActiveSpan(
142
+ args[0],
143
+ createActiveSpanHandler(args[1])
144
+ );
145
+ case 3:
146
+ return tracer.startActiveSpan(
147
+ args[0],
148
+ args[1],
149
+ createActiveSpanHandler(args[2])
150
+ );
151
+ case 4:
152
+ return tracer.startActiveSpan(
153
+ args[0],
154
+ args[1],
155
+ args[2],
156
+ createActiveSpanHandler(args[3])
157
+ );
158
+ }
159
+ };
160
+ var record = startActiveSpan;
161
+ var getCurrentSpan = () => import_api.trace.getActiveSpan();
162
+ var setAttributes = (attributes) => !!getCurrentSpan()?.setAttributes(attributes);
163
+ var opentelemetry = ({
164
+ serviceName = "Elysia",
165
+ instrumentations,
166
+ contextManager,
167
+ checkIfShouldTrace,
168
+ ...options
169
+ } = {}) => {
170
+ let tracer = import_api.trace.getTracer(serviceName);
171
+ if (shouldStartNodeSDK(import_api.trace.getTracerProvider())) {
172
+ const sdk = new import_sdk_node.NodeSDK({
173
+ ...options,
174
+ serviceName,
175
+ instrumentations
176
+ });
177
+ sdk.start();
178
+ tracer = import_api.trace.getTracer(serviceName);
179
+ } else {
180
+ }
181
+ if (!import_api.context._getContextManager?.() && contextManager)
182
+ try {
183
+ contextManager.enable();
184
+ import_api.context.setGlobalContextManager(contextManager);
185
+ } catch {
186
+ }
187
+ return new import_elysia.Elysia({
188
+ name: "@elysia/opentelemetry"
189
+ }).wrap((fn, request) => {
190
+ const shouldTrace = checkIfShouldTrace ? checkIfShouldTrace(request) : true;
191
+ if (!shouldTrace) return fn;
192
+ const headers = headerHasToJSON ? (
193
+ // @ts-ignore bun only
194
+ request.headers.toJSON()
195
+ ) : Object.fromEntries(request.headers.entries());
196
+ const ctx = import_api.propagation.extract(import_api.context.active(), headers);
197
+ return tracer.startActiveSpan(
198
+ "Root",
199
+ { kind: import_api.SpanKind.SERVER },
200
+ ctx,
201
+ (rootSpan) => {
202
+ const spanContext = import_api.trace.setSpan(ctx, rootSpan);
203
+ return (...args) => {
204
+ return import_api.context.with(spanContext, () => fn(...args));
205
+ };
206
+ }
207
+ );
208
+ }).trace(
209
+ { as: "global" },
210
+ ({
211
+ id,
212
+ onRequest,
213
+ onParse,
214
+ onTransform,
215
+ onBeforeHandle,
216
+ onHandle,
217
+ onAfterHandle,
218
+ onError,
219
+ onAfterResponse,
220
+ onMapResponse,
221
+ context,
222
+ context: {
223
+ path,
224
+ request: { method }
225
+ }
226
+ }) => {
227
+ const rootSpan = import_api.trace.getActiveSpan();
228
+ if (!rootSpan) return;
229
+ function setParent(span) {
230
+ if (span.ended) return;
231
+ if (rootSpan.ended) return void span.end();
232
+ const newContext = import_api.trace.setSpan(import_api.context.active(), span);
233
+ const currentContext = (
234
+ // @ts-expect-error private property
235
+ import_api.context.active()._currentContext
236
+ );
237
+ currentContext?.set(
238
+ contextKeySpan,
239
+ newContext.getValue(contextKeySpan)
240
+ );
241
+ }
242
+ function inspect(name) {
243
+ return function inspect2({
244
+ onEvent,
245
+ total,
246
+ onStop
247
+ }) {
248
+ if (total === 0 || // @ts-ignore
249
+ rootSpan.ended)
250
+ return;
251
+ tracer.startActiveSpan(
252
+ name,
253
+ {},
254
+ createContext(rootSpan),
255
+ (event) => {
256
+ if (
257
+ // @ts-ignore
258
+ rootSpan.ended
259
+ )
260
+ return;
261
+ onEvent(({ name: name2, onStop: onStop2 }) => {
262
+ const useChildSpan = total > 1;
263
+ let span;
264
+ if (useChildSpan) {
265
+ span = tracer.startSpan(
266
+ name2,
267
+ {},
268
+ createContext(event)
269
+ );
270
+ setParent(span);
271
+ } else {
272
+ setParent(event);
273
+ span = event;
274
+ }
275
+ onStop2(({ error }) => {
276
+ setParent(rootSpan);
277
+ if (span.ended || rootSpan.ended) return;
278
+ if (error) {
279
+ rootSpan.setStatus({
280
+ code: import_api.SpanStatusCode.ERROR,
281
+ message: error.message
282
+ });
283
+ span.setAttributes({
284
+ "error.type": error.constructor?.name ?? error.name,
285
+ "error.stack": error.stack
286
+ });
287
+ span.setStatus({
288
+ code: import_api.SpanStatusCode.ERROR,
289
+ message: error.message
290
+ });
291
+ } else {
292
+ rootSpan.setStatus({
293
+ code: import_api.SpanStatusCode.OK
294
+ });
295
+ span.setStatus({
296
+ code: import_api.SpanStatusCode.OK
297
+ });
298
+ }
299
+ if (useChildSpan) span.end();
300
+ });
301
+ });
302
+ onStop(() => {
303
+ setParent(rootSpan);
304
+ if (event.ended) return;
305
+ event.end();
306
+ });
307
+ }
308
+ );
309
+ };
310
+ }
311
+ const url = context.url;
312
+ const attributes = Object.assign(/* @__PURE__ */ Object.create(null), {
313
+ // ? Elysia Custom attribute
314
+ "http.request.id": id,
315
+ "http.request.method": method,
316
+ "url.path": path,
317
+ "url.full": url
318
+ });
319
+ if (context.qi && context.qi !== -1)
320
+ attributes["url.query"] = url.slice(
321
+ // @ts-ignore private property
322
+ context.qi + 1
323
+ );
324
+ const protocolSeparator = url.indexOf("://");
325
+ if (protocolSeparator > 0)
326
+ attributes["url.scheme"] = url.slice(0, protocolSeparator);
327
+ onRequest(inspect("Request"));
328
+ onParse(inspect("Parse"));
329
+ onTransform(inspect("Transform"));
330
+ onBeforeHandle(inspect("BeforeHandle"));
331
+ onHandle(({ onStop }) => {
332
+ const span = tracer.startSpan(
333
+ "Handle",
334
+ {},
335
+ createContext(rootSpan)
336
+ );
337
+ setParent(span);
338
+ onStop(({ error }) => {
339
+ setParent(rootSpan);
340
+ if (span.ended || rootSpan.ended) return;
341
+ if (error) {
342
+ rootSpan.setStatus({
343
+ code: import_api.SpanStatusCode.ERROR,
344
+ message: error.message
345
+ });
346
+ span.setStatus({
347
+ code: import_api.SpanStatusCode.ERROR,
348
+ message: error.message
349
+ });
350
+ span.recordException(error);
351
+ rootSpan.recordException(error);
352
+ } else {
353
+ rootSpan.setStatus({
354
+ code: import_api.SpanStatusCode.OK
355
+ });
356
+ span.setStatus({
357
+ code: import_api.SpanStatusCode.OK
358
+ });
359
+ }
360
+ span.end();
361
+ });
362
+ });
363
+ onAfterHandle(inspect("AfterHandle"));
364
+ onError((event) => {
365
+ inspect("Error")(event);
366
+ event.onStop(({ error }) => {
367
+ setParent(rootSpan);
368
+ if (rootSpan.ended) return;
369
+ {
370
+ let status = context.set.status;
371
+ if (typeof status === "string") {
372
+ status = import_elysia.StatusMap[status];
373
+ } else if (typeof status !== "number" && // @ts-ignore
374
+ typeof error?.status === "number")
375
+ status = error.status;
376
+ if (typeof status === "number") {
377
+ attributes["http.response.status_code"] = status;
378
+ if (status >= 500)
379
+ rootSpan.setStatus({
380
+ code: import_api.SpanStatusCode.ERROR
381
+ });
382
+ }
383
+ rootSpan.setAttributes(attributes);
384
+ }
385
+ if (
386
+ // @ts-ignore
387
+ !rootSpan.ended
388
+ )
389
+ rootSpan.end();
390
+ });
391
+ });
392
+ onMapResponse(inspect("MapResponse"));
393
+ onTransform(() => {
394
+ const { cookie, request, route, path: path2 } = context;
395
+ if (route)
396
+ rootSpan.updateName(
397
+ // @ts-ignore private property
398
+ `${method} ${route || path2}`
399
+ );
400
+ if (context.route) attributes["http.route"] = context.route;
401
+ {
402
+ let contentLength = request.headers.get("content-length");
403
+ if (contentLength) {
404
+ const number = parseNumericString(contentLength);
405
+ if (number)
406
+ attributes["http.request_content_length"] = number;
407
+ }
408
+ }
409
+ {
410
+ const userAgent = request.headers.get("User-Agent");
411
+ if (userAgent)
412
+ attributes["user_agent.original"] = userAgent;
413
+ }
414
+ const server = context.server;
415
+ if (server) {
416
+ attributes["server.port"] = server.port ?? 80;
417
+ attributes["server.address"] = server.url.hostname;
418
+ attributes["server.address"] = server.url.hostname;
419
+ }
420
+ let headers;
421
+ {
422
+ let hasHeaders;
423
+ let _headers;
424
+ if (context.headers) {
425
+ hasHeaders = true;
426
+ headers = context.headers;
427
+ _headers = Object.entries(context.headers);
428
+ } else if (hasHeaders = headerHasToJSON) {
429
+ headers = request.headers.toJSON();
430
+ _headers = Object.entries(headers);
431
+ } else {
432
+ headers = {};
433
+ _headers = request.headers.entries();
434
+ }
435
+ for (let [key, value] of _headers) {
436
+ key = key.toLowerCase();
437
+ if (hasHeaders) {
438
+ if (key === "user-agent") continue;
439
+ if (typeof value === "object")
440
+ attributes[`http.request.header.${key}`] = JSON.stringify(value);
441
+ else if (value !== void 0)
442
+ attributes[`http.request.header.${key}`] = value;
443
+ continue;
444
+ }
445
+ if (typeof value === "object")
446
+ headers[key] = attributes[`http.request.header.${key}`] = JSON.stringify(value);
447
+ else if (value !== void 0) {
448
+ if (key === "user-agent") {
449
+ headers[key] = value;
450
+ continue;
451
+ }
452
+ headers[key] = attributes[`http.request.header.${key}`] = value;
453
+ }
454
+ }
455
+ }
456
+ {
457
+ let headers2;
458
+ if (context.set.headers instanceof Headers) {
459
+ if (headerHasToJSON)
460
+ headers2 = Object.entries(
461
+ // @ts-ignore bun only
462
+ context.set.headers.toJSON()
463
+ );
464
+ else headers2 = context.set.headers.entries();
465
+ } else headers2 = Object.entries(context.set.headers);
466
+ for (let [key, value] of headers2) {
467
+ key = key.toLowerCase();
468
+ if (typeof value === "object")
469
+ attributes[`http.response.header.${key}`] = JSON.stringify(value);
470
+ else
471
+ attributes[`http.response.header.${key}`] = value;
472
+ }
473
+ }
474
+ if (context.ip)
475
+ attributes["client.address"] = context.ip;
476
+ else {
477
+ const ip = headers["true-client-ip"] ?? headers["cf-connection-ip"] ?? headers["x-forwarded-for"] ?? headers["x-real-ip"] ?? server?.requestIP(request);
478
+ if (ip)
479
+ attributes["client.address"] = typeof ip === "string" ? ip : ip.address ?? ip.toString();
480
+ }
481
+ if (cookie) {
482
+ const _cookie = {};
483
+ for (const [key, { value }] of Object.entries(cookie))
484
+ _cookie[key] = JSON.stringify(value);
485
+ attributes["http.request.cookie"] = JSON.stringify(_cookie);
486
+ }
487
+ rootSpan.setAttributes(attributes);
488
+ });
489
+ onParse(() => {
490
+ const body = context.body;
491
+ if (body !== void 0 && body !== null) {
492
+ const value = typeof body === "object" ? JSON.stringify(body) : body.toString();
493
+ attributes["http.request.body"] = value;
494
+ if (typeof body === "object") {
495
+ if (body instanceof Uint8Array)
496
+ attributes["http.request.body.size"] = body.length;
497
+ else if (body instanceof ArrayBuffer)
498
+ attributes["http.request.body.size"] = body.byteLength;
499
+ else if (body instanceof Blob)
500
+ attributes["http.request.body.size"] = body.size;
501
+ attributes["http.request.body.size"] = value.length;
502
+ } else {
503
+ attributes["http.request.body.size"] = value.length;
504
+ }
505
+ }
506
+ });
507
+ onMapResponse(() => {
508
+ const body = context.body;
509
+ if (body !== void 0 && body !== null) {
510
+ const value = typeof body === "object" ? JSON.stringify(body) : body.toString();
511
+ attributes["http.request.body"] = value;
512
+ if (typeof body === "object") {
513
+ if (body instanceof Uint8Array)
514
+ attributes["http.request.body.size"] = body.length;
515
+ else if (body instanceof ArrayBuffer)
516
+ attributes["http.request.body.size"] = body.byteLength;
517
+ else if (body instanceof Blob)
518
+ attributes["http.request.body.size"] = body.size;
519
+ attributes["http.request.body.size"] = value.length;
520
+ } else {
521
+ attributes["http.request.body.size"] = value.length;
522
+ }
523
+ }
524
+ {
525
+ let status = context.set.status ?? 200;
526
+ if (typeof status === "string")
527
+ status = import_elysia.StatusMap[status] ?? 200;
528
+ attributes["http.response.status_code"] = status;
529
+ }
530
+ const response = context.responseValue;
531
+ if (response !== void 0)
532
+ switch (typeof response) {
533
+ case "object":
534
+ if (response instanceof Response) {
535
+ } else if (response instanceof Uint8Array)
536
+ attributes["http.response.body.size"] = response.length;
537
+ else if (response instanceof ArrayBuffer)
538
+ attributes["http.response.body.size"] = response.byteLength;
539
+ else if (response instanceof Blob)
540
+ attributes["http.response.body.size"] = response.size;
541
+ else {
542
+ const value = JSON.stringify(response);
543
+ attributes["http.response.body"] = value;
544
+ attributes["http.response.body.size"] = value.length;
545
+ }
546
+ break;
547
+ default:
548
+ if (response === void 0 || response === null)
549
+ attributes["http.response.body.size"] = 0;
550
+ else {
551
+ const value = response.toString();
552
+ attributes["http.response.body"] = value;
553
+ attributes["http.response.body.size"] = value.length;
554
+ }
555
+ }
556
+ if (!rootSpan.ended) {
557
+ const statusCode = attributes["http.response.status_code"];
558
+ if (typeof statusCode === "number" && statusCode >= 500) {
559
+ rootSpan.setStatus({
560
+ code: import_api.SpanStatusCode.ERROR
561
+ });
562
+ }
563
+ rootSpan.setAttributes(attributes);
564
+ }
565
+ });
566
+ onAfterResponse((event) => {
567
+ inspect("AfterResponse")(event);
568
+ {
569
+ let status = context.set.status ?? 200;
570
+ if (typeof status === "string")
571
+ status = import_elysia.StatusMap[status] ?? 200;
572
+ attributes["http.response.status_code"] = status;
573
+ }
574
+ const body = context.body;
575
+ if (body !== void 0 && body !== null) {
576
+ const value = typeof body === "object" ? JSON.stringify(body) : body.toString();
577
+ attributes["http.request.body"] = value;
578
+ if (typeof body === "object") {
579
+ if (body instanceof Uint8Array)
580
+ attributes["http.request.body.size"] = body.length;
581
+ else if (body instanceof ArrayBuffer)
582
+ attributes["http.request.body.size"] = body.byteLength;
583
+ else if (body instanceof Blob)
584
+ attributes["http.request.body.size"] = body.size;
585
+ attributes["http.request.body.size"] = value.length;
586
+ } else {
587
+ attributes["http.request.body.size"] = value.length;
588
+ }
589
+ }
590
+ if (!rootSpan.ended) {
591
+ const statusCode = attributes["http.response.status_code"];
592
+ if (typeof statusCode === "number" && statusCode >= 500)
593
+ rootSpan.setStatus({
594
+ code: import_api.SpanStatusCode.ERROR
595
+ });
596
+ rootSpan.setAttributes(attributes);
597
+ }
598
+ event.onStop(() => {
599
+ setParent(rootSpan);
600
+ if (rootSpan.ended) return;
601
+ if (
602
+ // @ts-ignore
603
+ !rootSpan.ended
604
+ )
605
+ rootSpan.end();
606
+ });
607
+ });
608
+ context.request.signal.addEventListener("abort", () => {
609
+ const active = import_api.trace.getActiveSpan();
610
+ if (active && !active.ended) active.end();
611
+ if (rootSpan.ended) return;
612
+ rootSpan.setStatus({
613
+ code: import_api.SpanStatusCode.ERROR,
614
+ message: "Request aborted"
615
+ });
616
+ rootSpan.end();
617
+ });
618
+ }
619
+ );
620
+ };
621
+ // Annotate the CommonJS export names for ESM import in node:
622
+ 0 && (module.exports = {
623
+ contextKeySpan,
624
+ getCurrentSpan,
625
+ getTracer,
626
+ opentelemetry,
627
+ record,
628
+ setAttributes,
629
+ shouldStartNodeSDK,
630
+ startActiveSpan,
631
+ startSpan
632
+ });