@parsrun/service 0.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.
@@ -0,0 +1,820 @@
1
+ // src/tracing/context.ts
2
+ function generateTraceId() {
3
+ const bytes = new Uint8Array(16);
4
+ crypto.getRandomValues(bytes);
5
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
6
+ }
7
+ function generateSpanId() {
8
+ const bytes = new Uint8Array(8);
9
+ crypto.getRandomValues(bytes);
10
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
11
+ }
12
+ function createTraceContext(options) {
13
+ const ctx = {
14
+ traceId: options?.traceId ?? generateTraceId(),
15
+ spanId: options?.spanId ?? generateSpanId(),
16
+ traceFlags: options?.traceFlags ?? 1
17
+ // Default: sampled
18
+ };
19
+ if (options?.traceState) {
20
+ ctx.traceState = options.traceState;
21
+ }
22
+ return ctx;
23
+ }
24
+ function createChildContext(parent) {
25
+ const ctx = {
26
+ traceId: parent.traceId,
27
+ spanId: generateSpanId(),
28
+ traceFlags: parent.traceFlags
29
+ };
30
+ if (parent.traceState) {
31
+ ctx.traceState = parent.traceState;
32
+ }
33
+ return ctx;
34
+ }
35
+ function formatTraceparent(ctx) {
36
+ const version = "00";
37
+ const flags = ctx.traceFlags.toString(16).padStart(2, "0");
38
+ return `${version}-${ctx.traceId}-${ctx.spanId}-${flags}`;
39
+ }
40
+ function parseTraceparent(header) {
41
+ const parts = header.trim().split("-");
42
+ if (parts.length !== 4) {
43
+ return null;
44
+ }
45
+ const [version, traceId, spanId, flags] = parts;
46
+ if (version !== "00") {
47
+ return null;
48
+ }
49
+ if (!traceId || traceId.length !== 32 || !/^[0-9a-f]+$/i.test(traceId)) {
50
+ return null;
51
+ }
52
+ if (!spanId || spanId.length !== 16 || !/^[0-9a-f]+$/i.test(spanId)) {
53
+ return null;
54
+ }
55
+ if (!flags || flags.length !== 2 || !/^[0-9a-f]+$/i.test(flags)) {
56
+ return null;
57
+ }
58
+ return {
59
+ traceId: traceId.toLowerCase(),
60
+ spanId: spanId.toLowerCase(),
61
+ traceFlags: parseInt(flags, 16)
62
+ };
63
+ }
64
+ function formatTracestate(state) {
65
+ return Object.entries(state).map(([key, value]) => `${key}=${value}`).join(",");
66
+ }
67
+ function parseTracestate(header) {
68
+ const state = {};
69
+ for (const pair of header.split(",")) {
70
+ const [key, value] = pair.trim().split("=");
71
+ if (key && value) {
72
+ state[key] = value;
73
+ }
74
+ }
75
+ return state;
76
+ }
77
+ var TraceContextManager = class {
78
+ stack = [];
79
+ /**
80
+ * Get current trace context
81
+ */
82
+ current() {
83
+ return this.stack[this.stack.length - 1];
84
+ }
85
+ /**
86
+ * Run a function with a trace context
87
+ */
88
+ async run(ctx, fn) {
89
+ this.stack.push(ctx);
90
+ try {
91
+ return await fn();
92
+ } finally {
93
+ this.stack.pop();
94
+ }
95
+ }
96
+ /**
97
+ * Run a function with a new child context
98
+ */
99
+ async runChild(fn) {
100
+ const parent = this.current();
101
+ const child = parent ? createChildContext(parent) : createTraceContext();
102
+ return this.run(child, fn);
103
+ }
104
+ /**
105
+ * Create context from incoming request headers
106
+ */
107
+ fromHeaders(headers) {
108
+ const traceparent = headers instanceof Headers ? headers.get("traceparent") : headers["traceparent"];
109
+ if (!traceparent) {
110
+ return void 0;
111
+ }
112
+ const ctx = parseTraceparent(traceparent);
113
+ if (!ctx) {
114
+ return void 0;
115
+ }
116
+ const tracestate = headers instanceof Headers ? headers.get("tracestate") : headers["tracestate"];
117
+ if (tracestate) {
118
+ ctx.traceState = tracestate;
119
+ }
120
+ return ctx;
121
+ }
122
+ /**
123
+ * Add trace context to outgoing request headers
124
+ */
125
+ toHeaders(ctx) {
126
+ const headers = {
127
+ traceparent: formatTraceparent(ctx)
128
+ };
129
+ if (ctx.traceState) {
130
+ headers["tracestate"] = ctx.traceState;
131
+ }
132
+ return headers;
133
+ }
134
+ /**
135
+ * Check if current context is sampled
136
+ */
137
+ isSampled() {
138
+ const ctx = this.current();
139
+ return ctx ? (ctx.traceFlags & 1) === 1 : false;
140
+ }
141
+ /**
142
+ * Clear all contexts (for testing)
143
+ */
144
+ clear() {
145
+ this.stack.length = 0;
146
+ }
147
+ };
148
+ function shouldSample(sampler, traceId) {
149
+ if (sampler === "always") {
150
+ return true;
151
+ }
152
+ if (sampler === "never") {
153
+ return false;
154
+ }
155
+ if (traceId) {
156
+ const hash = parseInt(traceId.slice(-8), 16);
157
+ const threshold = Math.floor(sampler.ratio * 4294967295);
158
+ return hash < threshold;
159
+ }
160
+ return Math.random() < sampler.ratio;
161
+ }
162
+
163
+ // src/tracing/spans.ts
164
+ function createSpan(options) {
165
+ let traceContext;
166
+ if (options.parent) {
167
+ traceContext = {
168
+ traceId: options.parent.traceId,
169
+ spanId: generateSpanId(),
170
+ traceFlags: options.parent.traceFlags
171
+ };
172
+ if (options.parent.traceState) {
173
+ traceContext.traceState = options.parent.traceState;
174
+ }
175
+ } else {
176
+ traceContext = createTraceContext();
177
+ }
178
+ const span = {
179
+ name: options.name,
180
+ kind: options.kind ?? "internal",
181
+ traceContext,
182
+ startTime: options.startTime ?? Date.now(),
183
+ status: "unset",
184
+ attributes: options.attributes ?? {},
185
+ events: []
186
+ };
187
+ if (options.parent?.spanId) {
188
+ span.parentSpanId = options.parent.spanId;
189
+ }
190
+ return span;
191
+ }
192
+ var SpanManager = class {
193
+ spans = /* @__PURE__ */ new Map();
194
+ /**
195
+ * Start a new span
196
+ */
197
+ startSpan(options) {
198
+ const span = createSpan(options);
199
+ this.spans.set(span.traceContext.spanId, span);
200
+ return span;
201
+ }
202
+ /**
203
+ * End a span
204
+ */
205
+ endSpan(span, status) {
206
+ span.endTime = Date.now();
207
+ if (status) {
208
+ span.status = status;
209
+ } else if (span.status === "unset") {
210
+ span.status = "ok";
211
+ }
212
+ return span;
213
+ }
214
+ /**
215
+ * Set span attribute
216
+ */
217
+ setAttribute(span, key, value) {
218
+ span.attributes[key] = value;
219
+ }
220
+ /**
221
+ * Set multiple span attributes
222
+ */
223
+ setAttributes(span, attributes) {
224
+ Object.assign(span.attributes, attributes);
225
+ }
226
+ /**
227
+ * Add span event
228
+ */
229
+ addEvent(span, name, attributes) {
230
+ const event = {
231
+ name,
232
+ time: Date.now()
233
+ };
234
+ if (attributes) {
235
+ event.attributes = attributes;
236
+ }
237
+ span.events.push(event);
238
+ }
239
+ /**
240
+ * Set span status
241
+ */
242
+ setStatus(span, status) {
243
+ span.status = status;
244
+ }
245
+ /**
246
+ * Record exception on span
247
+ */
248
+ recordException(span, error) {
249
+ span.status = "error";
250
+ this.addEvent(span, "exception", {
251
+ "exception.type": error.name,
252
+ "exception.message": error.message,
253
+ "exception.stacktrace": error.stack ?? ""
254
+ });
255
+ }
256
+ /**
257
+ * Get span by ID
258
+ */
259
+ getSpan(spanId) {
260
+ return this.spans.get(spanId);
261
+ }
262
+ /**
263
+ * Get all completed spans and clear
264
+ */
265
+ flush() {
266
+ const completed = Array.from(this.spans.values()).filter((s) => s.endTime);
267
+ for (const span of completed) {
268
+ this.spans.delete(span.traceContext.spanId);
269
+ }
270
+ return completed;
271
+ }
272
+ /**
273
+ * Clear all spans
274
+ */
275
+ clear() {
276
+ this.spans.clear();
277
+ }
278
+ };
279
+ function getSpanDuration(span) {
280
+ if (!span.endTime) return void 0;
281
+ return span.endTime - span.startTime;
282
+ }
283
+ function isSpanCompleted(span) {
284
+ return span.endTime !== void 0;
285
+ }
286
+ function spanToLogObject(span) {
287
+ return {
288
+ traceId: span.traceContext.traceId,
289
+ spanId: span.traceContext.spanId,
290
+ parentSpanId: span.parentSpanId,
291
+ name: span.name,
292
+ kind: span.kind,
293
+ status: span.status,
294
+ startTime: new Date(span.startTime).toISOString(),
295
+ endTime: span.endTime ? new Date(span.endTime).toISOString() : void 0,
296
+ durationMs: getSpanDuration(span),
297
+ attributes: span.attributes,
298
+ events: span.events.map((e) => ({
299
+ name: e.name,
300
+ time: new Date(e.time).toISOString(),
301
+ attributes: e.attributes
302
+ }))
303
+ };
304
+ }
305
+ var SpanAttributes = {
306
+ // HTTP
307
+ HTTP_METHOD: "http.method",
308
+ HTTP_URL: "http.url",
309
+ HTTP_STATUS_CODE: "http.status_code",
310
+ HTTP_REQUEST_CONTENT_LENGTH: "http.request_content_length",
311
+ HTTP_RESPONSE_CONTENT_LENGTH: "http.response_content_length",
312
+ // RPC
313
+ RPC_SYSTEM: "rpc.system",
314
+ RPC_SERVICE: "rpc.service",
315
+ RPC_METHOD: "rpc.method",
316
+ // Database
317
+ DB_SYSTEM: "db.system",
318
+ DB_NAME: "db.name",
319
+ DB_OPERATION: "db.operation",
320
+ DB_STATEMENT: "db.statement",
321
+ // Messaging
322
+ MESSAGING_SYSTEM: "messaging.system",
323
+ MESSAGING_DESTINATION: "messaging.destination",
324
+ MESSAGING_MESSAGE_ID: "messaging.message_id",
325
+ // Service
326
+ SERVICE_NAME: "service.name",
327
+ SERVICE_VERSION: "service.version",
328
+ // Error
329
+ EXCEPTION_TYPE: "exception.type",
330
+ EXCEPTION_MESSAGE: "exception.message",
331
+ EXCEPTION_STACKTRACE: "exception.stacktrace",
332
+ // Custom Pars attributes
333
+ PARS_TENANT_ID: "pars.tenant_id",
334
+ PARS_USER_ID: "pars.user_id",
335
+ PARS_REQUEST_ID: "pars.request_id"
336
+ };
337
+
338
+ // src/tracing/exporters.ts
339
+ import { createLogger } from "@parsrun/core";
340
+ var ConsoleExporter = class {
341
+ name = "console";
342
+ logger;
343
+ pretty;
344
+ includeAttributes;
345
+ includeEvents;
346
+ constructor(options = {}) {
347
+ this.logger = options.logger ?? createLogger({ name: "trace-exporter" });
348
+ this.pretty = options.pretty ?? true;
349
+ this.includeAttributes = options.includeAttributes ?? true;
350
+ this.includeEvents = options.includeEvents ?? true;
351
+ }
352
+ async export(spans) {
353
+ for (const span of spans) {
354
+ const duration = getSpanDuration(span);
355
+ const status = span.status === "error" ? "ERROR" : span.status === "ok" ? "OK" : "UNSET";
356
+ if (this.pretty) {
357
+ const indent = span.parentSpanId ? " \u2514\u2500" : "\u2500\u2500";
358
+ const statusIcon = span.status === "error" ? "\u2717" : span.status === "ok" ? "\u2713" : "\u25CB";
359
+ const durationStr = duration !== void 0 ? `${duration}ms` : "?ms";
360
+ console.log(
361
+ `${indent} ${statusIcon} [${span.kind}] ${span.name} (${durationStr}) trace=${span.traceContext.traceId.slice(0, 8)}`
362
+ );
363
+ if (this.includeAttributes && Object.keys(span.attributes).length > 0) {
364
+ console.log(` attributes:`, span.attributes);
365
+ }
366
+ if (this.includeEvents && span.events.length > 0) {
367
+ for (const event of span.events) {
368
+ console.log(` event: ${event.name}`, event.attributes ?? "");
369
+ }
370
+ }
371
+ } else {
372
+ const logObj = spanToLogObject(span);
373
+ this.logger.info(`Span: ${span.name}`, {
374
+ ...logObj,
375
+ status,
376
+ durationMs: duration
377
+ });
378
+ }
379
+ }
380
+ }
381
+ async shutdown() {
382
+ }
383
+ };
384
+ function createConsoleExporter(options) {
385
+ return new ConsoleExporter(options);
386
+ }
387
+ var OtlpExporter = class {
388
+ name = "otlp";
389
+ endpoint;
390
+ serviceName;
391
+ serviceVersion;
392
+ headers;
393
+ timeout;
394
+ batchSize;
395
+ flushInterval;
396
+ logger;
397
+ buffer = [];
398
+ flushTimer = null;
399
+ constructor(options) {
400
+ this.endpoint = options.endpoint.replace(/\/$/, "");
401
+ this.serviceName = options.serviceName;
402
+ this.serviceVersion = options.serviceVersion ?? "1.0.0";
403
+ this.headers = options.headers ?? {};
404
+ this.timeout = options.timeout ?? 1e4;
405
+ this.batchSize = options.batchSize ?? 100;
406
+ this.flushInterval = options.flushInterval ?? 5e3;
407
+ this.logger = options.logger ?? createLogger({ name: "otlp-exporter" });
408
+ this.flushTimer = setInterval(() => this.flush(), this.flushInterval);
409
+ }
410
+ async export(spans) {
411
+ this.buffer.push(...spans);
412
+ if (this.buffer.length >= this.batchSize) {
413
+ await this.flush();
414
+ }
415
+ }
416
+ async flush() {
417
+ if (this.buffer.length === 0) return;
418
+ const spansToExport = this.buffer.splice(0, this.batchSize);
419
+ try {
420
+ const payload = this.buildOtlpPayload(spansToExport);
421
+ const controller = new AbortController();
422
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
423
+ try {
424
+ const response = await fetch(`${this.endpoint}/v1/traces`, {
425
+ method: "POST",
426
+ headers: {
427
+ "Content-Type": "application/json",
428
+ ...this.headers
429
+ },
430
+ body: JSON.stringify(payload),
431
+ signal: controller.signal
432
+ });
433
+ if (!response.ok) {
434
+ throw new Error(`OTLP export failed: ${response.status} ${response.statusText}`);
435
+ }
436
+ this.logger.debug(`Exported ${spansToExport.length} spans to OTLP`);
437
+ } finally {
438
+ clearTimeout(timeoutId);
439
+ }
440
+ } catch (error) {
441
+ this.logger.error(`Failed to export spans to OTLP`, error);
442
+ this.buffer.unshift(...spansToExport);
443
+ }
444
+ }
445
+ buildOtlpPayload(spans) {
446
+ return {
447
+ resourceSpans: [
448
+ {
449
+ resource: {
450
+ attributes: [
451
+ { key: "service.name", value: { stringValue: this.serviceName } },
452
+ { key: "service.version", value: { stringValue: this.serviceVersion } }
453
+ ]
454
+ },
455
+ scopeSpans: [
456
+ {
457
+ scope: {
458
+ name: "@parsrun/service",
459
+ version: "0.1.0"
460
+ },
461
+ spans: spans.map((span) => this.convertSpan(span))
462
+ }
463
+ ]
464
+ }
465
+ ]
466
+ };
467
+ }
468
+ convertSpan(span) {
469
+ const otlpSpan = {
470
+ traceId: span.traceContext.traceId,
471
+ spanId: span.traceContext.spanId,
472
+ name: span.name,
473
+ kind: this.convertSpanKind(span.kind),
474
+ startTimeUnixNano: String(span.startTime * 1e6),
475
+ attributes: Object.entries(span.attributes).map(([key, value]) => ({
476
+ key,
477
+ value: this.convertAttributeValue(value)
478
+ })),
479
+ events: span.events.map((event) => ({
480
+ name: event.name,
481
+ timeUnixNano: String(event.time * 1e6),
482
+ attributes: event.attributes ? Object.entries(event.attributes).map(([key, value]) => ({
483
+ key,
484
+ value: this.convertAttributeValue(value)
485
+ })) : []
486
+ })),
487
+ status: {
488
+ code: span.status === "error" ? 2 : span.status === "ok" ? 1 : 0
489
+ }
490
+ };
491
+ if (span.parentSpanId) {
492
+ otlpSpan.parentSpanId = span.parentSpanId;
493
+ }
494
+ if (span.endTime) {
495
+ otlpSpan.endTimeUnixNano = String(span.endTime * 1e6);
496
+ }
497
+ return otlpSpan;
498
+ }
499
+ convertSpanKind(kind) {
500
+ switch (kind) {
501
+ case "internal":
502
+ return 1;
503
+ case "server":
504
+ return 2;
505
+ case "client":
506
+ return 3;
507
+ case "producer":
508
+ return 4;
509
+ case "consumer":
510
+ return 5;
511
+ default:
512
+ return 0;
513
+ }
514
+ }
515
+ convertAttributeValue(value) {
516
+ if (typeof value === "string") {
517
+ return { stringValue: value };
518
+ }
519
+ if (typeof value === "number") {
520
+ if (Number.isInteger(value)) {
521
+ return { intValue: String(value) };
522
+ }
523
+ return { doubleValue: value };
524
+ }
525
+ if (typeof value === "boolean") {
526
+ return { boolValue: value };
527
+ }
528
+ if (Array.isArray(value)) {
529
+ return {
530
+ arrayValue: {
531
+ values: value.map((v) => this.convertAttributeValue(v))
532
+ }
533
+ };
534
+ }
535
+ return { stringValue: String(value) };
536
+ }
537
+ async shutdown() {
538
+ if (this.flushTimer) {
539
+ clearInterval(this.flushTimer);
540
+ this.flushTimer = null;
541
+ }
542
+ await this.flush();
543
+ }
544
+ };
545
+ function createOtlpExporter(options) {
546
+ return new OtlpExporter(options);
547
+ }
548
+
549
+ // src/tracing/tracer.ts
550
+ import { createLogger as createLogger2 } from "@parsrun/core";
551
+ var Tracer = class {
552
+ serviceName;
553
+ serviceVersion;
554
+ sampler;
555
+ exporter;
556
+ logger;
557
+ contextManager;
558
+ spanManager;
559
+ enabled;
560
+ flushTimer = null;
561
+ constructor(options) {
562
+ this.serviceName = options.serviceName;
563
+ this.serviceVersion = options.serviceVersion ?? "1.0.0";
564
+ this.enabled = options.config?.enabled ?? true;
565
+ this.sampler = options.config?.sampler ?? { ratio: 0.1 };
566
+ this.exporter = options.exporter ?? new ConsoleExporter();
567
+ this.logger = options.logger ?? createLogger2({ name: `tracer:${options.serviceName}` });
568
+ this.contextManager = new TraceContextManager();
569
+ this.spanManager = new SpanManager();
570
+ if (this.enabled) {
571
+ this.flushTimer = setInterval(() => this.flush(), 5e3);
572
+ }
573
+ }
574
+ /**
575
+ * Start a new span
576
+ */
577
+ startSpan(name, options) {
578
+ if (!this.enabled) return null;
579
+ const parent = options?.parent ?? this.contextManager.current();
580
+ if (!parent && !shouldSample(this.sampler)) {
581
+ return null;
582
+ }
583
+ const spanOptions = {
584
+ name,
585
+ kind: options?.kind ?? "internal",
586
+ attributes: {
587
+ [SpanAttributes.SERVICE_NAME]: this.serviceName,
588
+ [SpanAttributes.SERVICE_VERSION]: this.serviceVersion,
589
+ ...options?.attributes
590
+ }
591
+ };
592
+ if (parent) {
593
+ spanOptions.parent = parent;
594
+ }
595
+ const span = this.spanManager.startSpan(spanOptions);
596
+ return span;
597
+ }
598
+ /**
599
+ * End a span
600
+ */
601
+ endSpan(span, error) {
602
+ if (!span) return;
603
+ if (error) {
604
+ this.spanManager.recordException(span, error);
605
+ }
606
+ this.spanManager.endSpan(span, error ? "error" : "ok");
607
+ }
608
+ /**
609
+ * Run a function with automatic span creation
610
+ */
611
+ async trace(name, fn, options) {
612
+ const span = this.startSpan(name, options);
613
+ if (!span) {
614
+ return fn(null);
615
+ }
616
+ try {
617
+ const result = await this.contextManager.run(span.traceContext, () => fn(span));
618
+ this.endSpan(span);
619
+ return result;
620
+ } catch (error) {
621
+ this.endSpan(span, error);
622
+ throw error;
623
+ }
624
+ }
625
+ /**
626
+ * Add attribute to current span
627
+ */
628
+ setAttribute(key, value) {
629
+ const ctx = this.contextManager.current();
630
+ if (!ctx) return;
631
+ const span = this.spanManager.getSpan(ctx.spanId);
632
+ if (span) {
633
+ this.spanManager.setAttribute(span, key, value);
634
+ }
635
+ }
636
+ /**
637
+ * Add event to current span
638
+ */
639
+ addEvent(name, attributes) {
640
+ const ctx = this.contextManager.current();
641
+ if (!ctx) return;
642
+ const span = this.spanManager.getSpan(ctx.spanId);
643
+ if (span) {
644
+ this.spanManager.addEvent(span, name, attributes);
645
+ }
646
+ }
647
+ /**
648
+ * Get current trace context
649
+ */
650
+ currentContext() {
651
+ return this.contextManager.current();
652
+ }
653
+ /**
654
+ * Get context manager for advanced use
655
+ */
656
+ getContextManager() {
657
+ return this.contextManager;
658
+ }
659
+ /**
660
+ * Extract trace context from incoming request
661
+ */
662
+ extract(headers) {
663
+ return this.contextManager.fromHeaders(headers);
664
+ }
665
+ /**
666
+ * Inject trace context into outgoing request headers
667
+ */
668
+ inject(ctx) {
669
+ const context = ctx ?? this.contextManager.current();
670
+ if (!context) return {};
671
+ return this.contextManager.toHeaders(context);
672
+ }
673
+ /**
674
+ * Flush completed spans to exporter
675
+ */
676
+ async flush() {
677
+ const spans = this.spanManager.flush();
678
+ if (spans.length > 0) {
679
+ try {
680
+ await this.exporter.export(spans);
681
+ } catch (error) {
682
+ this.logger.error("Failed to export spans", error);
683
+ }
684
+ }
685
+ }
686
+ /**
687
+ * Shutdown tracer
688
+ */
689
+ async shutdown() {
690
+ if (this.flushTimer) {
691
+ clearInterval(this.flushTimer);
692
+ this.flushTimer = null;
693
+ }
694
+ await this.flush();
695
+ await this.exporter.shutdown();
696
+ this.spanManager.clear();
697
+ this.contextManager.clear();
698
+ }
699
+ };
700
+ function createTracer(options) {
701
+ return new Tracer(options);
702
+ }
703
+ var globalTracer = null;
704
+ function getGlobalTracer() {
705
+ return globalTracer;
706
+ }
707
+ function setGlobalTracer(tracer) {
708
+ globalTracer = tracer;
709
+ }
710
+ function resetGlobalTracer() {
711
+ globalTracer = null;
712
+ }
713
+ function createTracingMiddleware(tracer) {
714
+ return async (request, next) => {
715
+ const parentCtx = tracer.extract(request.headers);
716
+ const url = new URL(request.url);
717
+ const spanOpts = {
718
+ kind: "server",
719
+ attributes: {
720
+ [SpanAttributes.HTTP_METHOD]: request.method,
721
+ [SpanAttributes.HTTP_URL]: request.url
722
+ }
723
+ };
724
+ if (parentCtx) {
725
+ spanOpts.parent = parentCtx;
726
+ }
727
+ const span = tracer.startSpan(`${request.method} ${url.pathname}`, spanOpts);
728
+ if (!span) {
729
+ return next();
730
+ }
731
+ try {
732
+ const response = await tracer.getContextManager().run(span.traceContext, next);
733
+ tracer.endSpan(span);
734
+ span.attributes[SpanAttributes.HTTP_STATUS_CODE] = response.status;
735
+ return response;
736
+ } catch (error) {
737
+ tracer.endSpan(span, error);
738
+ throw error;
739
+ }
740
+ };
741
+ }
742
+ function createRpcTracing(tracer) {
743
+ return {
744
+ /**
745
+ * Trace an outgoing RPC call
746
+ */
747
+ async traceCall(service, method, fn) {
748
+ return tracer.trace(
749
+ `rpc.${service}.${method}`,
750
+ fn,
751
+ {
752
+ kind: "client",
753
+ attributes: {
754
+ [SpanAttributes.RPC_SYSTEM]: "pars",
755
+ [SpanAttributes.RPC_SERVICE]: service,
756
+ [SpanAttributes.RPC_METHOD]: method
757
+ }
758
+ }
759
+ );
760
+ },
761
+ /**
762
+ * Trace an incoming RPC request
763
+ */
764
+ async traceHandler(service, method, fn, parentCtx) {
765
+ const handlerOpts = {
766
+ kind: "server",
767
+ attributes: {
768
+ [SpanAttributes.RPC_SYSTEM]: "pars",
769
+ [SpanAttributes.RPC_SERVICE]: service,
770
+ [SpanAttributes.RPC_METHOD]: method
771
+ }
772
+ };
773
+ if (parentCtx) {
774
+ handlerOpts.parent = parentCtx;
775
+ }
776
+ const span = tracer.startSpan(`rpc.${service}.${method}`, handlerOpts);
777
+ if (!span) {
778
+ return fn();
779
+ }
780
+ try {
781
+ const result = await tracer.getContextManager().run(span.traceContext, fn);
782
+ tracer.endSpan(span);
783
+ return result;
784
+ } catch (error) {
785
+ tracer.endSpan(span, error);
786
+ throw error;
787
+ }
788
+ }
789
+ };
790
+ }
791
+ export {
792
+ ConsoleExporter,
793
+ OtlpExporter,
794
+ SpanAttributes,
795
+ SpanManager,
796
+ TraceContextManager,
797
+ Tracer,
798
+ createChildContext,
799
+ createConsoleExporter,
800
+ createOtlpExporter,
801
+ createRpcTracing,
802
+ createSpan,
803
+ createTraceContext,
804
+ createTracer,
805
+ createTracingMiddleware,
806
+ formatTraceparent,
807
+ formatTracestate,
808
+ generateSpanId,
809
+ generateTraceId,
810
+ getGlobalTracer,
811
+ getSpanDuration,
812
+ isSpanCompleted,
813
+ parseTraceparent,
814
+ parseTracestate,
815
+ resetGlobalTracer,
816
+ setGlobalTracer,
817
+ shouldSample,
818
+ spanToLogObject
819
+ };
820
+ //# sourceMappingURL=index.js.map