@dxos/tracing 0.8.4-main.fffef41 → 0.8.4-staging.ac66bdf99f

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.
Files changed (39) hide show
  1. package/dist/lib/browser/index.mjs +328 -339
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +328 -339
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/api.d.ts +36 -17
  8. package/dist/types/src/api.d.ts.map +1 -1
  9. package/dist/types/src/buffering-backend.d.ts +24 -0
  10. package/dist/types/src/buffering-backend.d.ts.map +1 -0
  11. package/dist/types/src/diagnostic.d.ts +2 -2
  12. package/dist/types/src/diagnostic.d.ts.map +1 -1
  13. package/dist/types/src/index.d.ts +1 -2
  14. package/dist/types/src/index.d.ts.map +1 -1
  15. package/dist/types/src/remote/index.d.ts +0 -1
  16. package/dist/types/src/remote/index.d.ts.map +1 -1
  17. package/dist/types/src/symbols.d.ts +0 -1
  18. package/dist/types/src/symbols.d.ts.map +1 -1
  19. package/dist/types/src/trace-processor.d.ts +16 -52
  20. package/dist/types/src/trace-processor.d.ts.map +1 -1
  21. package/dist/types/src/tracing-types.d.ts +67 -0
  22. package/dist/types/src/tracing-types.d.ts.map +1 -0
  23. package/dist/types/tsconfig.tsbuildinfo +1 -1
  24. package/package.json +13 -9
  25. package/src/api.ts +237 -35
  26. package/src/buffering-backend.ts +112 -0
  27. package/src/diagnostic.ts +2 -2
  28. package/src/index.ts +1 -2
  29. package/src/remote/index.ts +0 -1
  30. package/src/symbols.ts +0 -2
  31. package/src/trace-processor.ts +58 -258
  32. package/src/tracing-types.ts +77 -0
  33. package/src/tracing.test.ts +513 -4
  34. package/dist/types/src/remote/tracing.d.ts +0 -23
  35. package/dist/types/src/remote/tracing.d.ts.map +0 -1
  36. package/dist/types/src/trace-sender.d.ts +0 -9
  37. package/dist/types/src/trace-sender.d.ts.map +0 -1
  38. package/src/remote/tracing.ts +0 -53
  39. package/src/trace-sender.ts +0 -88
@@ -1,23 +1,107 @@
1
1
  import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
2
 
3
3
  // src/api.ts
4
- import { Context as Context2 } from "@dxos/context";
4
+ import { Context as Context2, LifecycleState, Resource, TRACE_SPAN_ATTRIBUTE } from "@dxos/context";
5
5
 
6
6
  // src/symbols.ts
7
- var symbolTracingContext = Symbol("dxos.tracing.context");
7
+ var symbolTracingContext = /* @__PURE__ */ Symbol("dxos.tracing.context");
8
8
  var getTracingContext = (target) => {
9
9
  return target[symbolTracingContext] ??= {
10
10
  infoProperties: {},
11
11
  metricsProperties: {}
12
12
  };
13
13
  };
14
- var TRACE_SPAN_ATTRIBUTE = "dxos.trace-span";
15
14
 
16
15
  // src/trace-processor.ts
17
- import { unrefTimeout } from "@dxos/async";
18
- import { LogLevel, getContextFromEntry, log } from "@dxos/log";
16
+ import { LogLevel, log } from "@dxos/log";
19
17
  import { getPrototypeSpecificInstanceId } from "@dxos/util";
20
18
 
19
+ // src/buffering-backend.ts
20
+ var BUFFERED_PREFIX = "buffered-";
21
+ var BufferedSpan = class {
22
+ options;
23
+ spanContext;
24
+ startTime;
25
+ delegate;
26
+ #ended = false;
27
+ #endTime;
28
+ #error;
29
+ #hasError = false;
30
+ constructor(options, id) {
31
+ this.options = options;
32
+ this.spanContext = {
33
+ traceparent: `${BUFFERED_PREFIX}${id}`
34
+ };
35
+ this.startTime = Date.now();
36
+ }
37
+ end(endTime) {
38
+ if (this.delegate) {
39
+ this.delegate.end(endTime);
40
+ return;
41
+ }
42
+ this.#endTime = endTime ?? Date.now();
43
+ this.#ended = true;
44
+ }
45
+ setError(err) {
46
+ if (this.delegate) {
47
+ this.delegate.setError?.(err);
48
+ return;
49
+ }
50
+ this.#error = err;
51
+ this.#hasError = true;
52
+ }
53
+ replay(real) {
54
+ if (this.#hasError) {
55
+ real.setError?.(this.#error);
56
+ }
57
+ if (this.#ended) {
58
+ real.end(this.#endTime);
59
+ } else {
60
+ this.delegate = real;
61
+ }
62
+ }
63
+ };
64
+ var BufferingTracingBackend = class {
65
+ #pending = [];
66
+ #counter = 0;
67
+ startSpan(options) {
68
+ const span2 = new BufferedSpan(options, ++this.#counter);
69
+ this.#pending.push(span2);
70
+ return span2;
71
+ }
72
+ /** Discard all buffered spans without replaying them. */
73
+ clear() {
74
+ this.#pending.length = 0;
75
+ }
76
+ /**
77
+ * Replay all buffered spans into {@link backend}.
78
+ *
79
+ * @returns Map from synthetic buffered traceparent to real {@link TraceContextData},
80
+ * used by the post-drain translating wrapper to resolve stale buffered IDs
81
+ * still present on in-flight {@link Context} objects.
82
+ */
83
+ drain(backend) {
84
+ const idMap = /* @__PURE__ */ new Map();
85
+ for (const buffered of this.#pending) {
86
+ let parentContext = buffered.options.parentContext;
87
+ if (parentContext && parentContext.traceparent.startsWith(BUFFERED_PREFIX)) {
88
+ parentContext = idMap.get(parentContext.traceparent) ?? parentContext;
89
+ }
90
+ const real = backend.startSpan({
91
+ ...buffered.options,
92
+ parentContext,
93
+ startTime: buffered.startTime
94
+ });
95
+ if (real.spanContext) {
96
+ idMap.set(buffered.spanContext.traceparent, real.spanContext);
97
+ }
98
+ buffered.replay(real);
99
+ }
100
+ this.#pending.length = 0;
101
+ return idMap;
102
+ }
103
+ };
104
+
21
105
  // src/diagnostic.ts
22
106
  import { asyncTimeout } from "@dxos/async";
23
107
  import { invariant } from "@dxos/invariant";
@@ -284,124 +368,6 @@ var RemoteMetrics = class {
284
368
  }
285
369
  };
286
370
 
287
- // src/remote/tracing.ts
288
- var RemoteTracing = class {
289
- _tracing;
290
- _spanMap = /* @__PURE__ */ new Map();
291
- registerProcessor(processor) {
292
- this._tracing = processor;
293
- }
294
- flushSpan(span2) {
295
- if (!this._tracing) {
296
- return;
297
- }
298
- if (!span2.endTs) {
299
- const remoteSpan = this._tracing.startSpan({
300
- name: span2.methodName,
301
- op: span2.op ?? "function",
302
- attributes: span2.attributes
303
- });
304
- this._spanMap.set(span2, remoteSpan);
305
- } else {
306
- const remoteSpan = this._spanMap.get(span2);
307
- if (remoteSpan) {
308
- remoteSpan.end();
309
- this._spanMap.delete(span2);
310
- }
311
- }
312
- }
313
- };
314
-
315
- // src/trace-sender.ts
316
- import { Stream } from "@dxos/codec-protobuf/stream";
317
- var TraceSender = class {
318
- _traceProcessor;
319
- constructor(_traceProcessor) {
320
- this._traceProcessor = _traceProcessor;
321
- }
322
- streamTrace(request) {
323
- return new Stream(({ ctx, next }) => {
324
- const flushEvents = (resources, spans2, logs) => {
325
- const event = {
326
- resourceAdded: [],
327
- resourceRemoved: [],
328
- spanAdded: [],
329
- logAdded: []
330
- };
331
- if (resources) {
332
- for (const id of resources) {
333
- const entry = this._traceProcessor.resources.get(id);
334
- if (entry) {
335
- event.resourceAdded.push({
336
- resource: entry.data
337
- });
338
- } else {
339
- event.resourceRemoved.push({
340
- id
341
- });
342
- }
343
- }
344
- } else {
345
- for (const entry of this._traceProcessor.resources.values()) {
346
- event.resourceAdded.push({
347
- resource: entry.data
348
- });
349
- }
350
- }
351
- if (spans2) {
352
- for (const id of spans2) {
353
- const span2 = this._traceProcessor.spans.get(id);
354
- if (span2) {
355
- event.spanAdded.push({
356
- span: span2
357
- });
358
- }
359
- }
360
- } else {
361
- for (const span2 of this._traceProcessor.spans.values()) {
362
- event.spanAdded.push({
363
- span: span2
364
- });
365
- }
366
- }
367
- if (logs) {
368
- for (const log2 of logs) {
369
- event.logAdded.push({
370
- log: log2
371
- });
372
- }
373
- } else {
374
- for (const log2 of this._traceProcessor.logs) {
375
- event.logAdded.push({
376
- log: log2
377
- });
378
- }
379
- }
380
- if (event.resourceAdded.length > 0 || event.resourceRemoved.length > 0 || event.spanAdded.length > 0) {
381
- next(event);
382
- }
383
- };
384
- const flush = () => {
385
- flushEvents(subscription.dirtyResources, subscription.dirtySpans, subscription.newLogs);
386
- subscription.dirtyResources.clear();
387
- subscription.dirtySpans.clear();
388
- subscription.newLogs.length = 0;
389
- };
390
- const subscription = {
391
- flush,
392
- dirtyResources: /* @__PURE__ */ new Set(),
393
- dirtySpans: /* @__PURE__ */ new Set(),
394
- newLogs: []
395
- };
396
- this._traceProcessor.subscriptions.add(subscription);
397
- ctx.onDispose(() => {
398
- this._traceProcessor.subscriptions.delete(subscription);
399
- });
400
- flushEvents(null, null, null);
401
- });
402
- }
403
- };
404
-
405
371
  // src/weak-ref.ts
406
372
  var WeakRefMock = class {
407
373
  // eslint-disable-next-line @typescript-eslint/no-useless-constructor
@@ -436,35 +402,61 @@ var ResourceEntry = class {
436
402
  }
437
403
  };
438
404
  var MAX_RESOURCE_RECORDS = 2e3;
439
- var MAX_SPAN_RECORDS = 1e3;
440
405
  var MAX_LOG_RECORDS = 1e3;
441
- var REFRESH_INTERVAL = 1e3;
442
406
  var MAX_INFO_OBJECT_DEPTH = 8;
443
- var IS_CLOUDFLARE_WORKERS = !!globalThis?.navigator?.userAgent?.includes("Cloudflare-Workers");
444
407
  var TraceProcessor = class {
445
408
  diagnostics = new DiagnosticsManager();
446
409
  diagnosticsChannel = new DiagnosticsChannel();
447
410
  remoteMetrics = new RemoteMetrics();
448
- remoteTracing = new RemoteTracing();
449
- subscriptions = /* @__PURE__ */ new Set();
411
+ #bufferingBackend = new BufferingTracingBackend();
412
+ #activeBackend = this.#bufferingBackend;
413
+ /**
414
+ * Tracing backend. Initially a buffering backend that records spans;
415
+ * once the observability package sets a real backend, the buffer is drained
416
+ * and a thin translating wrapper is installed that resolves stale buffered
417
+ * parent IDs still held by in-flight {@link Context} objects.
418
+ *
419
+ * The wrapper only allocates when a `buffered-*` parent is actually encountered;
420
+ * the common path is a single `startsWith` check and direct passthrough.
421
+ */
422
+ get tracingBackend() {
423
+ return this.#activeBackend;
424
+ }
425
+ set tracingBackend(backend) {
426
+ if (!backend || backend === this.#bufferingBackend) {
427
+ this.#bufferingBackend.clear();
428
+ this.#activeBackend = this.#bufferingBackend;
429
+ return;
430
+ }
431
+ const idMap = this.#bufferingBackend.drain(backend);
432
+ this.#activeBackend = {
433
+ startSpan: (options) => {
434
+ const parent = options.parentContext;
435
+ if (parent?.traceparent.startsWith(BUFFERED_PREFIX)) {
436
+ const translated = idMap.get(parent.traceparent);
437
+ if (translated) {
438
+ return backend.startSpan({
439
+ ...options,
440
+ parentContext: translated
441
+ });
442
+ }
443
+ }
444
+ return backend.startSpan(options);
445
+ }
446
+ };
447
+ }
450
448
  resources = /* @__PURE__ */ new Map();
451
449
  resourceInstanceIndex = /* @__PURE__ */ new WeakMap();
452
450
  resourceIdList = [];
453
- spans = /* @__PURE__ */ new Map();
454
- spanIdList = [];
455
451
  logs = [];
456
452
  _instanceTag = null;
457
453
  constructor() {
458
454
  log.addProcessor(this._logProcessor.bind(this), void 0, {
459
455
  F: __dxlog_file3,
460
- L: 103,
456
+ L: 108,
461
457
  S: this,
462
458
  C: (f, a) => f(...a)
463
459
  });
464
- if (!IS_CLOUDFLARE_WORKERS) {
465
- const refreshInterval = setInterval(this.refresh.bind(this), REFRESH_INTERVAL);
466
- unrefTimeout(refreshInterval);
467
- }
468
460
  if (DiagnosticsChannel.supported) {
469
461
  this.diagnosticsChannel.serve(this.diagnostics);
470
462
  }
@@ -474,10 +466,7 @@ var TraceProcessor = class {
474
466
  this._instanceTag = tag;
475
467
  this.diagnostics.setInstanceTag(tag);
476
468
  }
477
- /**
478
- * @internal
479
- */
480
- // TODO(burdon): Comment.
469
+ /** @internal */
481
470
  createTraceResource(params) {
482
471
  const id = this.resources.size;
483
472
  const tracingContext = getTracingContext(Object.getPrototypeOf(params.instance));
@@ -498,24 +487,10 @@ var TraceProcessor = class {
498
487
  if (this.resourceIdList.length > MAX_RESOURCE_RECORDS) {
499
488
  this._clearResources();
500
489
  }
501
- this._markResourceDirty(id);
502
- }
503
- createTraceSender() {
504
- return new TraceSender(this);
505
- }
506
- traceSpan(params) {
507
- const span2 = new TracingSpan(this, params);
508
- this._flushSpan(span2);
509
- return span2;
510
490
  }
511
491
  // TODO(burdon): Not implemented.
512
492
  addLink(parent, child, opts) {
513
493
  }
514
- //
515
- // Getters
516
- //
517
- // TODO(burdon): Define type.
518
- // TODO(burdon): Reconcile with system service.
519
494
  getDiagnostics() {
520
495
  this.refresh();
521
496
  return {
@@ -523,7 +498,6 @@ var TraceProcessor = class {
523
498
  `${entry.sanitizedClassName}#${entry.data.instanceId}`,
524
499
  entry.data
525
500
  ])),
526
- spans: Array.from(this.spans.values()),
527
501
  logs: this.logs.filter((log2) => log2.level >= LogLevel.INFO)
528
502
  };
529
503
  }
@@ -578,43 +552,8 @@ var TraceProcessor = class {
578
552
  for (const key of Object.keys(tracingContext.metricsProperties)) {
579
553
  instance[key]._tick?.(time);
580
554
  }
581
- let _changed = false;
582
- const oldInfo = resource2.data.info;
583
555
  resource2.data.info = this.getResourceInfo(instance);
584
- _changed ||= !areEqualShallow(oldInfo, resource2.data.info);
585
- const oldMetrics = resource2.data.metrics;
586
556
  resource2.data.metrics = this.getResourceMetrics(instance);
587
- _changed ||= !areEqualShallow(oldMetrics, resource2.data.metrics);
588
- this._markResourceDirty(resource2.data.id);
589
- }
590
- for (const subscription of this.subscriptions) {
591
- subscription.flush();
592
- }
593
- }
594
- //
595
- // Implementation
596
- //
597
- /**
598
- * @internal
599
- */
600
- _flushSpan(runtimeSpan) {
601
- const span2 = runtimeSpan.serialize();
602
- this.spans.set(span2.id, span2);
603
- this.spanIdList.push(span2.id);
604
- if (this.spanIdList.length > MAX_SPAN_RECORDS) {
605
- this._clearSpans();
606
- }
607
- this._markSpanDirty(span2.id);
608
- this.remoteTracing.flushSpan(runtimeSpan);
609
- }
610
- _markResourceDirty(id) {
611
- for (const subscription of this.subscriptions) {
612
- subscription.dirtyResources.add(id);
613
- }
614
- }
615
- _markSpanDirty(id) {
616
- for (const subscription of this.subscriptions) {
617
- subscription.dirtySpans.add(id);
618
557
  }
619
558
  }
620
559
  _clearResources() {
@@ -623,20 +562,11 @@ var TraceProcessor = class {
623
562
  this.resources.delete(id);
624
563
  }
625
564
  }
626
- _clearSpans() {
627
- while (this.spanIdList.length > MAX_SPAN_RECORDS) {
628
- const id = this.spanIdList.shift();
629
- this.spans.delete(id);
630
- }
631
- }
632
565
  _pushLog(log2) {
633
566
  this.logs.push(log2);
634
567
  if (this.logs.length > MAX_LOG_RECORDS) {
635
568
  this.logs.shift();
636
569
  }
637
- for (const subscription of this.subscriptions) {
638
- subscription.newLogs.push(log2);
639
- }
640
570
  }
641
571
  _logProcessor = (config, entry) => {
642
572
  switch (entry.level) {
@@ -648,18 +578,21 @@ var TraceProcessor = class {
648
578
  if (!resource2) {
649
579
  return;
650
580
  }
651
- const context = getContextFromEntry(entry) ?? {};
652
- for (const key of Object.keys(context)) {
653
- context[key] = sanitizeValue(context[key], 0, this);
581
+ const context = {
582
+ ...entry.computedContext
583
+ };
584
+ if (entry.computedError !== void 0) {
585
+ context.error = entry.computedError;
654
586
  }
587
+ const { filename, line } = entry.computedMeta;
655
588
  const entryToPush = {
656
589
  level: entry.level,
657
- message: entry.message ?? (entry.error ? entry.error.message ?? String(entry.error) : ""),
590
+ message: entry.message ?? entry.computedError ?? "",
658
591
  context,
659
- timestamp: /* @__PURE__ */ new Date(),
592
+ timestamp: new Date(entry.timestamp),
660
593
  meta: {
661
- file: entry.meta?.F ?? "",
662
- line: entry.meta?.L ?? 0,
594
+ file: filename ?? "",
595
+ line: line ?? 0,
663
596
  resourceId: resource2.data.id
664
597
  }
665
598
  };
@@ -670,94 +603,6 @@ var TraceProcessor = class {
670
603
  }
671
604
  };
672
605
  };
673
- var TracingSpan = class _TracingSpan {
674
- _traceProcessor;
675
- static nextId = 0;
676
- id;
677
- parentId = null;
678
- methodName;
679
- resourceId = null;
680
- op;
681
- attributes;
682
- startTs;
683
- endTs = null;
684
- error = null;
685
- _showInBrowserTimeline;
686
- _ctx = null;
687
- constructor(_traceProcessor, params) {
688
- this._traceProcessor = _traceProcessor;
689
- this.id = _TracingSpan.nextId++;
690
- this.methodName = params.methodName;
691
- this.resourceId = _traceProcessor.getResourceId(params.instance);
692
- this.startTs = performance.now();
693
- this._showInBrowserTimeline = params.showInBrowserTimeline;
694
- this.op = params.op;
695
- this.attributes = params.attributes ?? {};
696
- if (params.parentCtx) {
697
- this._ctx = params.parentCtx.derive({
698
- attributes: {
699
- [TRACE_SPAN_ATTRIBUTE]: this.id
700
- }
701
- });
702
- const parentId = params.parentCtx.getAttribute(TRACE_SPAN_ATTRIBUTE);
703
- if (typeof parentId === "number") {
704
- this.parentId = parentId;
705
- }
706
- }
707
- }
708
- get name() {
709
- const resource2 = this._traceProcessor.resources.get(this.resourceId);
710
- return resource2 ? `${resource2.sanitizedClassName}#${resource2.data.instanceId}.${this.methodName}` : this.methodName;
711
- }
712
- get ctx() {
713
- return this._ctx;
714
- }
715
- markSuccess() {
716
- this.endTs = performance.now();
717
- this._traceProcessor._flushSpan(this);
718
- if (this._showInBrowserTimeline) {
719
- this._markInBrowserTimeline();
720
- }
721
- }
722
- markError(err) {
723
- this.endTs = performance.now();
724
- this.error = serializeError(err);
725
- this._traceProcessor._flushSpan(this);
726
- if (this._showInBrowserTimeline) {
727
- this._markInBrowserTimeline();
728
- }
729
- }
730
- serialize() {
731
- return {
732
- id: this.id,
733
- resourceId: this.resourceId ?? void 0,
734
- methodName: this.methodName,
735
- parentId: this.parentId ?? void 0,
736
- startTs: this.startTs.toFixed(3),
737
- endTs: this.endTs?.toFixed(3) ?? void 0,
738
- error: this.error ?? void 0
739
- };
740
- }
741
- _markInBrowserTimeline() {
742
- if (typeof globalThis?.performance?.measure === "function") {
743
- performance.measure(this.name, {
744
- start: this.startTs,
745
- end: this.endTs
746
- });
747
- }
748
- }
749
- };
750
- var serializeError = (err) => {
751
- if (err instanceof Error) {
752
- return {
753
- name: err.name,
754
- message: err.message
755
- };
756
- }
757
- return {
758
- message: String(err)
759
- };
760
- };
761
606
  var TRACE_PROCESSOR = globalThis.TRACE_PROCESSOR ??= new TraceProcessor();
762
607
  var sanitizeValue = (value, depth, traceProcessor) => {
763
608
  switch (typeof value) {
@@ -804,33 +649,46 @@ var sanitizeValue = (value, depth, traceProcessor) => {
804
649
  return value.toString();
805
650
  }
806
651
  };
807
- var areEqualShallow = (a, b) => {
808
- for (const key in a) {
809
- if (!(key in b) || a[key] !== b[key]) {
810
- return false;
811
- }
812
- }
813
- for (const key in b) {
814
- if (!(key in a) || a[key] !== b[key]) {
815
- return false;
816
- }
817
- }
818
- return true;
819
- };
820
652
  var sanitizeClassName = (className) => {
653
+ let name = className.replace(/^_+/, "");
821
654
  const SANITIZE_REGEX = /[^_](\d+)$/;
822
- const m = className.match(SANITIZE_REGEX);
823
- if (!m) {
824
- return className;
825
- } else {
826
- return className.slice(0, -m[1].length);
655
+ const m = name.match(SANITIZE_REGEX);
656
+ if (m) {
657
+ name = name.slice(0, -m[1].length);
827
658
  }
659
+ return name;
828
660
  };
829
661
  var isSetLike = (value) => value instanceof Set || typeof value === "object" && value !== null && Object.getPrototypeOf(value).constructor.name === "ComplexSet";
830
662
  var isMapLike = (value) => value instanceof Map || typeof value === "object" && value !== null && Object.getPrototypeOf(value).constructor.name === "ComplexMap";
831
663
 
832
664
  // src/api.ts
665
+ var __dxlog_file4 = "/__w/dxos/dxos/packages/common/tracing/src/api.ts";
666
+ var LIFECYCLE_SPAN = /* @__PURE__ */ Symbol("dxos.tracing.lifecycle-span");
667
+ var TRACE_ALL_KEY = "dxos.debug.traceAll";
668
+ var collectSpanAttributes = (instance, spanAttributes) => {
669
+ const proto = Object.getPrototypeOf(instance);
670
+ if (!proto) {
671
+ return;
672
+ }
673
+ const tracingContext = getTracingContext(proto);
674
+ for (const [key, { options }] of Object.entries(tracingContext.infoProperties)) {
675
+ if (!options.spanAttribute) {
676
+ continue;
677
+ }
678
+ try {
679
+ const value = typeof instance[key] === "function" ? instance[key]() : instance[key];
680
+ if (value != null) {
681
+ const resolved = options.enum ? options.enum[value] : String(value);
682
+ spanAttributes[`ctx.${key}`] = resolved;
683
+ }
684
+ } catch {
685
+ }
686
+ }
687
+ };
833
688
  var resource = (options) => (constructor) => {
689
+ if (options?.lifecycle && !(constructor.prototype instanceof Resource)) {
690
+ throw new Error(`@trace.resource({ lifecycle: true }) requires ${constructor.name} to extend Resource`);
691
+ }
834
692
  const klass = /* @__PURE__ */ (() => class extends constructor {
835
693
  constructor(...rest) {
836
694
  super(...rest);
@@ -841,6 +699,68 @@ var resource = (options) => (constructor) => {
841
699
  });
842
700
  }
843
701
  })();
702
+ if (options?.lifecycle) {
703
+ const sanitizedName = sanitizeClassName(constructor.name);
704
+ const proto = klass.prototype;
705
+ const originalOpen = proto.open;
706
+ const originalClose = proto.close;
707
+ proto.open = async function(ctx) {
708
+ const self = this;
709
+ if (self._lifecycleState !== LifecycleState.CLOSED) {
710
+ return originalOpen.call(this, ctx);
711
+ }
712
+ const parentSpanContext = ctx?.getAttribute(TRACE_SPAN_ATTRIBUTE);
713
+ const resourceEntry = TRACE_PROCESSOR.resourceInstanceIndex.get(this);
714
+ const spanAttributes = {};
715
+ if (resourceEntry) {
716
+ spanAttributes.entryPoint = resourceEntry.sanitizedClassName;
717
+ }
718
+ const remoteSpan = TRACE_PROCESSOR.tracingBackend?.startSpan({
719
+ name: `${sanitizedName}.lifecycle`,
720
+ op: "lifecycle",
721
+ attributes: spanAttributes,
722
+ parentContext: parentSpanContext
723
+ });
724
+ self[LIFECYCLE_SPAN] = remoteSpan;
725
+ let openCtx = ctx;
726
+ if (remoteSpan?.spanContext != null) {
727
+ const traceAttrs = {
728
+ [TRACE_SPAN_ATTRIBUTE]: remoteSpan.spanContext
729
+ };
730
+ openCtx = ctx ? ctx.derive({
731
+ attributes: traceAttrs
732
+ }) : new Context2({
733
+ attributes: traceAttrs
734
+ }, {
735
+ F: __dxlog_file4,
736
+ L: 104
737
+ });
738
+ }
739
+ try {
740
+ return await originalOpen.call(this, openCtx);
741
+ } catch (err) {
742
+ remoteSpan?.setError?.(err);
743
+ remoteSpan?.end();
744
+ self[LIFECYCLE_SPAN] = void 0;
745
+ throw err;
746
+ }
747
+ };
748
+ proto.close = async function(ctx) {
749
+ const self = this;
750
+ const remoteSpan = self[LIFECYCLE_SPAN];
751
+ try {
752
+ return await originalClose.call(this, ctx);
753
+ } catch (err) {
754
+ remoteSpan?.setError?.(err);
755
+ throw err;
756
+ } finally {
757
+ if (remoteSpan) {
758
+ remoteSpan.end();
759
+ self[LIFECYCLE_SPAN] = void 0;
760
+ }
761
+ }
762
+ };
763
+ }
844
764
  Object.defineProperty(klass, "name", {
845
765
  value: constructor.name
846
766
  });
@@ -854,45 +774,117 @@ var info = (opts = {}) => (target, propertyKey, descriptor) => {
854
774
  var mark = (name) => {
855
775
  performance.mark(name);
856
776
  };
857
- var span = ({ showInBrowserTimeline = false, op, attributes } = {}) => (target, propertyKey, descriptor) => {
777
+ var span = ({ showInBrowserTimeline = false, showInRemoteTracing = true, op, attributes } = {}) => (target, propertyKey, descriptor) => {
858
778
  const method = descriptor.value;
859
779
  descriptor.value = async function(...args) {
860
780
  const parentCtx = args[0] instanceof Context2 ? args[0] : null;
861
- const span2 = TRACE_PROCESSOR.traceSpan({
862
- parentCtx,
863
- methodName: propertyKey,
864
- instance: this,
865
- showInBrowserTimeline,
866
- op,
867
- attributes
868
- });
869
- const callArgs = span2.ctx ? [
870
- span2.ctx,
871
- ...args.slice(1)
872
- ] : args;
781
+ const startTs = performance.now();
782
+ const parentSpanContext = parentCtx?.getAttribute(TRACE_SPAN_ATTRIBUTE);
783
+ const resourceEntry = TRACE_PROCESSOR.resourceInstanceIndex.get(this);
784
+ const className = resourceEntry?.sanitizedClassName ?? sanitizeClassName(target.constructor?.name ?? "unknown");
785
+ const spanName = `${className}.${propertyKey}`;
786
+ const spanAttributes = {};
787
+ if (resourceEntry) {
788
+ spanAttributes.entryPoint = resourceEntry.sanitizedClassName;
789
+ }
790
+ collectSpanAttributes(this, spanAttributes);
791
+ if (attributes) {
792
+ for (const [key, value] of Object.entries(attributes)) {
793
+ spanAttributes[key.startsWith("ctx.") ? key : `ctx.${key}`] = value;
794
+ }
795
+ }
796
+ const remoteSpan = showInRemoteTracing ? TRACE_PROCESSOR.tracingBackend?.startSpan({
797
+ name: spanName,
798
+ op: op ?? "function",
799
+ attributes: spanAttributes,
800
+ parentContext: parentSpanContext
801
+ }) : void 0;
802
+ let callArgs = args;
803
+ if (parentCtx) {
804
+ const childCtx = remoteSpan?.spanContext != null ? parentCtx.derive({
805
+ attributes: {
806
+ [TRACE_SPAN_ATTRIBUTE]: remoteSpan.spanContext
807
+ }
808
+ }) : parentCtx.derive();
809
+ callArgs = [
810
+ childCtx,
811
+ ...args.slice(1)
812
+ ];
813
+ }
873
814
  try {
874
815
  return await method.apply(this, callArgs);
875
816
  } catch (err) {
876
- span2.markError(err);
817
+ remoteSpan?.setError?.(err);
877
818
  throw err;
878
819
  } finally {
879
- span2.markSuccess();
820
+ remoteSpan?.end();
821
+ if (showInBrowserTimeline && typeof globalThis?.performance?.measure === "function") {
822
+ performance.measure(spanName, {
823
+ start: startTs,
824
+ end: performance.now()
825
+ });
826
+ }
880
827
  }
881
828
  };
882
829
  };
883
- var spans = /* @__PURE__ */ new Map();
830
+ var manualSpans = /* @__PURE__ */ new Map();
831
+ var manualSpanTimestamps = /* @__PURE__ */ new Map();
884
832
  var spanStart = (params) => {
885
- if (spans.has(params.id)) {
886
- return;
833
+ if (manualSpans.has(params.id) || manualSpanTimestamps.has(params.id)) {
834
+ return params.parentCtx;
835
+ }
836
+ const resourceEntry = TRACE_PROCESSOR.resourceInstanceIndex.get(params.instance);
837
+ const className = resourceEntry?.sanitizedClassName ?? "unknown";
838
+ const spanName = `${className}.${params.methodName}`;
839
+ if (params.showInBrowserTimeline) {
840
+ manualSpanTimestamps.set(params.id, {
841
+ name: spanName,
842
+ startTs: performance.now()
843
+ });
844
+ }
845
+ if (params.showInRemoteTracing === false || !TRACE_PROCESSOR.tracingBackend) {
846
+ return params.parentCtx;
847
+ }
848
+ const parentSpanContext = params.parentCtx?.getAttribute(TRACE_SPAN_ATTRIBUTE);
849
+ const spanAttributes = {};
850
+ if (resourceEntry) {
851
+ spanAttributes.entryPoint = resourceEntry.sanitizedClassName;
852
+ }
853
+ collectSpanAttributes(params.instance, spanAttributes);
854
+ if (params.attributes) {
855
+ for (const [key, value] of Object.entries(params.attributes)) {
856
+ spanAttributes[key.startsWith("ctx.") ? key : `ctx.${key}`] = value;
857
+ }
887
858
  }
888
- const span2 = TRACE_PROCESSOR.traceSpan(params);
889
- spans.set(params.id, span2);
859
+ const remoteSpan = TRACE_PROCESSOR.tracingBackend.startSpan({
860
+ name: spanName,
861
+ op: params.op ?? "function",
862
+ attributes: spanAttributes,
863
+ parentContext: parentSpanContext
864
+ });
865
+ manualSpans.set(params.id, remoteSpan);
866
+ if (params.parentCtx && remoteSpan.spanContext != null) {
867
+ return params.parentCtx.derive({
868
+ attributes: {
869
+ [TRACE_SPAN_ATTRIBUTE]: remoteSpan.spanContext
870
+ }
871
+ });
872
+ }
873
+ return params.parentCtx;
890
874
  };
891
875
  var spanEnd = (id) => {
892
- const span2 = spans.get(id);
893
- if (span2) {
894
- span2.markSuccess();
895
- spans.delete(id);
876
+ const remoteSpan = manualSpans.get(id);
877
+ if (remoteSpan) {
878
+ remoteSpan.end();
879
+ manualSpans.delete(id);
880
+ }
881
+ const timestamps = manualSpanTimestamps.get(id);
882
+ if (timestamps && typeof globalThis?.performance?.measure === "function") {
883
+ performance.measure(timestamps.name, {
884
+ start: timestamps.startTs,
885
+ end: performance.now()
886
+ });
887
+ manualSpanTimestamps.delete(id);
896
888
  }
897
889
  };
898
890
  var metricsCounter = () => (target, propertyKey, descriptor) => {
@@ -1110,16 +1102,13 @@ export {
1110
1102
  DiagnosticsManager,
1111
1103
  MapCounter,
1112
1104
  RemoteMetrics,
1113
- RemoteTracing,
1114
1105
  ResourceEntry,
1106
+ TRACE_ALL_KEY,
1115
1107
  TRACE_PROCESSOR,
1116
- TRACE_SPAN_ATTRIBUTE,
1117
1108
  TimeSeriesCounter,
1118
1109
  TimeUsageCounter,
1119
1110
  TraceDiagnosticImpl,
1120
1111
  TraceProcessor,
1121
- TraceSender,
1122
- TracingSpan,
1123
1112
  UnaryCounter,
1124
1113
  getTracingContext,
1125
1114
  sanitizeClassName,