@dxos/tracing 0.8.4-main.b97322e → 0.8.4-main.bcb3aa67d6

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.
@@ -1,10 +1,10 @@
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 Context3 } 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: {},
@@ -15,6 +15,7 @@ var TRACE_SPAN_ATTRIBUTE = "dxos.trace-span";
15
15
 
16
16
  // src/trace-processor.ts
17
17
  import { unrefTimeout } from "@dxos/async";
18
+ import { Context as Context2 } from "@dxos/context";
18
19
  import { LogLevel, getContextFromEntry, log } from "@dxos/log";
19
20
  import { getPrototypeSpecificInstanceId } from "@dxos/util";
20
21
 
@@ -29,6 +30,10 @@ var createId = () => Math.random().toString(36).slice(2);
29
30
  var __dxlog_file = "/__w/dxos/dxos/packages/common/tracing/src/diagnostic.ts";
30
31
  var DIAGNOSTICS_TIMEOUT = 1e4;
31
32
  var TraceDiagnosticImpl = class {
33
+ id;
34
+ fetch;
35
+ name;
36
+ _onUnregister;
32
37
  constructor(id, fetch, name, _onUnregister) {
33
38
  this.id = id;
34
39
  this.fetch = fetch;
@@ -40,11 +45,9 @@ var TraceDiagnosticImpl = class {
40
45
  }
41
46
  };
42
47
  var DiagnosticsManager = class {
43
- constructor() {
44
- this.instanceId = createId();
45
- this.registry = /* @__PURE__ */ new Map();
46
- this._instanceTag = null;
47
- }
48
+ instanceId = createId();
49
+ registry = /* @__PURE__ */ new Map();
50
+ _instanceTag = null;
48
51
  get instanceTag() {
49
52
  return this._instanceTag;
50
53
  }
@@ -117,17 +120,19 @@ var __dxlog_file2 = "/__w/dxos/dxos/packages/common/tracing/src/diagnostics-chan
117
120
  var DEFAULT_CHANNEL_NAME = "dxos-diagnostics";
118
121
  var DISCOVER_TIME = 500;
119
122
  var DiagnosticsChannel = class _DiagnosticsChannel {
123
+ _channelName;
120
124
  static get supported() {
121
125
  return globalThis.BroadcastChannel != null;
122
126
  }
127
+ _ctx = new Context(void 0, {
128
+ F: __dxlog_file2,
129
+ L: 46
130
+ });
131
+ // Separate channels becauase the client and server may be in the same process.
132
+ _serveChannel = void 0;
133
+ _clientChannel = void 0;
123
134
  constructor(_channelName = DEFAULT_CHANNEL_NAME) {
124
135
  this._channelName = _channelName;
125
- this._ctx = new Context(void 0, {
126
- F: __dxlog_file2,
127
- L: 46
128
- });
129
- this._serveChannel = void 0;
130
- this._clientChannel = void 0;
131
136
  if (_DiagnosticsChannel.supported) {
132
137
  this._serveChannel = new BroadcastChannel(_channelName);
133
138
  this._clientChannel = new BroadcastChannel(_channelName);
@@ -262,9 +267,7 @@ var DiagnosticsChannel = class _DiagnosticsChannel {
262
267
 
263
268
  // src/remote/metrics.ts
264
269
  var RemoteMetrics = class {
265
- constructor() {
266
- this._metrics = /* @__PURE__ */ new Set();
267
- }
270
+ _metrics = /* @__PURE__ */ new Set();
268
271
  registerProcessor(processor) {
269
272
  this._metrics.add(processor);
270
273
  }
@@ -283,30 +286,132 @@ var RemoteMetrics = class {
283
286
  };
284
287
 
285
288
  // src/remote/tracing.ts
289
+ var MAX_ENDED_CONTEXTS = 1e4;
286
290
  var RemoteTracing = class {
287
- constructor() {
288
- this._spanMap = /* @__PURE__ */ new Map();
289
- }
291
+ _tracing;
292
+ _spanMap = /* @__PURE__ */ new Map();
293
+ _idToSpan = /* @__PURE__ */ new Map();
294
+ /**
295
+ * Retains OTEL span contexts after spans end so that periodic/background
296
+ * operations referencing a completed parent (via `this._ctx`) still produce
297
+ * correlated child spans instead of orphaned root traces.
298
+ */
299
+ _endedSpanContexts = /* @__PURE__ */ new Map();
300
+ /**
301
+ * Buffers flushSpan calls that arrive before a processor is registered,
302
+ * so early startup spans are not silently dropped.
303
+ */
304
+ _pendingFlushes = [];
290
305
  registerProcessor(processor) {
291
306
  this._tracing = processor;
307
+ const pending = this._pendingFlushes;
308
+ this._pendingFlushes = null;
309
+ if (pending) {
310
+ for (const { span: span2, isEnd } of pending) {
311
+ this._replayFlush(span2, isEnd);
312
+ }
313
+ }
314
+ }
315
+ /** Returns the opaque OTEL context for the given DXOS span ID, if one exists. */
316
+ getSpanContext(spanId) {
317
+ const tracingSpan = this._idToSpan.get(spanId);
318
+ if (tracingSpan) {
319
+ return this._spanMap.get(tracingSpan)?.spanContext;
320
+ }
321
+ return this._endedSpanContexts.get(spanId);
322
+ }
323
+ /** Wraps execution so that the remote span is active as parent context. */
324
+ wrapExecution(span2, fn) {
325
+ const remoteSpan = this._spanMap.get(span2);
326
+ if (remoteSpan?.wrapExecution) {
327
+ return remoteSpan.wrapExecution(fn);
328
+ }
329
+ return fn();
292
330
  }
293
331
  flushSpan(span2) {
332
+ if (!span2.showInRemoteTracing) {
333
+ return;
334
+ }
294
335
  if (!this._tracing) {
336
+ this._pendingFlushes?.push({
337
+ span: span2,
338
+ isEnd: !!span2.endTs
339
+ });
295
340
  return;
296
341
  }
297
342
  if (!span2.endTs) {
298
- const remoteSpan = this._tracing.startSpan({
299
- name: span2.methodName,
300
- op: span2.op ?? "function",
301
- attributes: span2.attributes
302
- });
303
- this._spanMap.set(span2, remoteSpan);
343
+ this._startRemoteSpan(span2);
304
344
  } else {
305
- const remoteSpan = this._spanMap.get(span2);
306
- if (remoteSpan) {
307
- remoteSpan.end();
308
- this._spanMap.delete(span2);
345
+ this._endRemoteSpan(span2);
346
+ }
347
+ }
348
+ _startRemoteSpan(span2) {
349
+ let parentContext;
350
+ if (span2.parentId != null) {
351
+ const parentTracingSpan = this._idToSpan.get(span2.parentId);
352
+ if (parentTracingSpan) {
353
+ parentContext = this._spanMap.get(parentTracingSpan)?.spanContext;
354
+ }
355
+ if (parentContext == null) {
356
+ parentContext = this._endedSpanContexts.get(span2.parentId);
357
+ }
358
+ }
359
+ const attributes = {};
360
+ if (span2.sanitizedClassName) {
361
+ attributes.entryPoint = span2.sanitizedClassName;
362
+ }
363
+ for (const [key, value] of Object.entries(span2.attributes)) {
364
+ attributes[key.startsWith("ctx.") ? key : `ctx.${key}`] = value;
365
+ }
366
+ const remoteSpan = this._tracing.startSpan({
367
+ name: span2.name,
368
+ op: span2.op ?? "function",
369
+ attributes,
370
+ parentContext
371
+ });
372
+ this._spanMap.set(span2, remoteSpan);
373
+ this._idToSpan.set(span2.id, span2);
374
+ }
375
+ _endRemoteSpan(span2) {
376
+ const remoteSpan = this._spanMap.get(span2);
377
+ if (remoteSpan) {
378
+ if (remoteSpan.spanContext != null) {
379
+ this._endedSpanContexts.set(span2.id, remoteSpan.spanContext);
380
+ this._evictEndedContexts();
381
+ }
382
+ remoteSpan.end();
383
+ this._spanMap.delete(span2);
384
+ this._idToSpan.delete(span2.id);
385
+ }
386
+ }
387
+ /**
388
+ * Replays a buffered flush that was queued before the processor was registered.
389
+ * For spans that started AND ended before registration, replays both events.
390
+ */
391
+ _replayFlush(span2, isEnd) {
392
+ if (!isEnd) {
393
+ this._startRemoteSpan(span2);
394
+ if (span2.endTs != null) {
395
+ this._endRemoteSpan(span2);
396
+ }
397
+ } else {
398
+ if (!this._spanMap.has(span2)) {
399
+ this._startRemoteSpan(span2);
400
+ }
401
+ this._endRemoteSpan(span2);
402
+ }
403
+ }
404
+ _evictEndedContexts() {
405
+ if (this._endedSpanContexts.size <= MAX_ENDED_CONTEXTS) {
406
+ return;
407
+ }
408
+ const iterator = this._endedSpanContexts.keys();
409
+ while (this._endedSpanContexts.size > MAX_ENDED_CONTEXTS) {
410
+ const oldest = iterator.next();
411
+ if (oldest.done) {
412
+ break;
309
413
  }
414
+ this._endedSpanContexts.delete(oldest.value);
310
415
  }
311
416
  }
312
417
  };
@@ -314,6 +419,7 @@ var RemoteTracing = class {
314
419
  // src/trace-sender.ts
315
420
  import { Stream } from "@dxos/codec-protobuf/stream";
316
421
  var TraceSender = class {
422
+ _traceProcessor;
317
423
  constructor(_traceProcessor) {
318
424
  this._traceProcessor = _traceProcessor;
319
425
  }
@@ -414,6 +520,15 @@ var WeakRef = globalThis.WeakRef ?? WeakRefMock;
414
520
  // src/trace-processor.ts
415
521
  var __dxlog_file3 = "/__w/dxos/dxos/packages/common/tracing/src/trace-processor.ts";
416
522
  var ResourceEntry = class {
523
+ data;
524
+ instance;
525
+ annotation;
526
+ /**
527
+ * Sometimes bundlers mangle class names: WebFile -> WebFile2.
528
+ *
529
+ * We use a heuristic to remove the suffix.
530
+ */
531
+ sanitizedClassName;
417
532
  constructor(data, instance, annotation) {
418
533
  this.data = data;
419
534
  this.instance = instance;
@@ -431,53 +546,22 @@ var REFRESH_INTERVAL = 1e3;
431
546
  var MAX_INFO_OBJECT_DEPTH = 8;
432
547
  var IS_CLOUDFLARE_WORKERS = !!globalThis?.navigator?.userAgent?.includes("Cloudflare-Workers");
433
548
  var TraceProcessor = class {
549
+ diagnostics = new DiagnosticsManager();
550
+ diagnosticsChannel = new DiagnosticsChannel();
551
+ remoteMetrics = new RemoteMetrics();
552
+ remoteTracing = new RemoteTracing();
553
+ subscriptions = /* @__PURE__ */ new Set();
554
+ resources = /* @__PURE__ */ new Map();
555
+ resourceInstanceIndex = /* @__PURE__ */ new WeakMap();
556
+ resourceIdList = [];
557
+ spans = /* @__PURE__ */ new Map();
558
+ spanIdList = [];
559
+ logs = [];
560
+ _instanceTag = null;
434
561
  constructor() {
435
- this.diagnostics = new DiagnosticsManager();
436
- this.diagnosticsChannel = new DiagnosticsChannel();
437
- this.remoteMetrics = new RemoteMetrics();
438
- this.remoteTracing = new RemoteTracing();
439
- this.subscriptions = /* @__PURE__ */ new Set();
440
- this.resources = /* @__PURE__ */ new Map();
441
- this.resourceInstanceIndex = /* @__PURE__ */ new WeakMap();
442
- this.resourceIdList = [];
443
- this.spans = /* @__PURE__ */ new Map();
444
- this.spanIdList = [];
445
- this.logs = [];
446
- this._instanceTag = null;
447
- this._logProcessor = (config, entry) => {
448
- switch (entry.level) {
449
- case LogLevel.ERROR:
450
- case LogLevel.WARN:
451
- case LogLevel.TRACE: {
452
- const scope = entry.meta?.S;
453
- const resource2 = this.resourceInstanceIndex.get(scope);
454
- if (!resource2) {
455
- return;
456
- }
457
- const context = getContextFromEntry(entry) ?? {};
458
- for (const key of Object.keys(context)) {
459
- context[key] = sanitizeValue(context[key], 0, this);
460
- }
461
- const entryToPush = {
462
- level: entry.level,
463
- message: entry.message ?? (entry.error ? entry.error.message ?? String(entry.error) : ""),
464
- context,
465
- timestamp: /* @__PURE__ */ new Date(),
466
- meta: {
467
- file: entry.meta?.F ?? "",
468
- line: entry.meta?.L ?? 0,
469
- resourceId: resource2.data.id
470
- }
471
- };
472
- this._pushLog(entryToPush);
473
- break;
474
- }
475
- default:
476
- }
477
- };
478
562
  log.addProcessor(this._logProcessor.bind(this), void 0, {
479
563
  F: __dxlog_file3,
480
- L: 103,
564
+ L: 104,
481
565
  S: this,
482
566
  C: (f, a) => f(...a)
483
567
  });
@@ -658,31 +742,73 @@ var TraceProcessor = class {
658
742
  subscription.newLogs.push(log2);
659
743
  }
660
744
  }
745
+ _logProcessor = (config, entry) => {
746
+ switch (entry.level) {
747
+ case LogLevel.ERROR:
748
+ case LogLevel.WARN:
749
+ case LogLevel.TRACE: {
750
+ const scope = entry.meta?.S;
751
+ const resource2 = this.resourceInstanceIndex.get(scope);
752
+ if (!resource2) {
753
+ return;
754
+ }
755
+ const context = getContextFromEntry(entry) ?? {};
756
+ for (const key of Object.keys(context)) {
757
+ context[key] = sanitizeValue(context[key], 0, this);
758
+ }
759
+ const entryToPush = {
760
+ level: entry.level,
761
+ message: entry.message ?? (entry.error ? entry.error.message ?? String(entry.error) : ""),
762
+ context,
763
+ timestamp: /* @__PURE__ */ new Date(),
764
+ meta: {
765
+ file: entry.meta?.F ?? "",
766
+ line: entry.meta?.L ?? 0,
767
+ resourceId: resource2.data.id
768
+ }
769
+ };
770
+ this._pushLog(entryToPush);
771
+ break;
772
+ }
773
+ default:
774
+ }
775
+ };
661
776
  };
662
777
  var TracingSpan = class _TracingSpan {
663
- static {
664
- this.nextId = 0;
665
- }
778
+ _traceProcessor;
779
+ static nextId = 0;
780
+ id;
781
+ parentId = null;
782
+ methodName;
783
+ resourceId = null;
784
+ op;
785
+ attributes;
786
+ startTs;
787
+ endTs = null;
788
+ error = null;
789
+ _showInBrowserTimeline;
790
+ _showInRemoteTracing;
791
+ _ctx;
666
792
  constructor(_traceProcessor, params) {
667
793
  this._traceProcessor = _traceProcessor;
668
- this.parentId = null;
669
- this.resourceId = null;
670
- this.endTs = null;
671
- this.error = null;
672
- this._ctx = null;
673
794
  this.id = _TracingSpan.nextId++;
674
795
  this.methodName = params.methodName;
675
796
  this.resourceId = _traceProcessor.getResourceId(params.instance);
676
797
  this.startTs = performance.now();
677
798
  this._showInBrowserTimeline = params.showInBrowserTimeline;
799
+ this._showInRemoteTracing = params.showInRemoteTracing ?? true;
678
800
  this.op = params.op;
679
801
  this.attributes = params.attributes ?? {};
802
+ const baseCtx = params.parentCtx ?? new Context2(void 0, {
803
+ F: __dxlog_file3,
804
+ L: 397
805
+ });
806
+ this._ctx = this._showInRemoteTracing ? baseCtx.derive({
807
+ attributes: {
808
+ [TRACE_SPAN_ATTRIBUTE]: this.id
809
+ }
810
+ }) : baseCtx.derive();
680
811
  if (params.parentCtx) {
681
- this._ctx = params.parentCtx.derive({
682
- attributes: {
683
- [TRACE_SPAN_ATTRIBUTE]: this.id
684
- }
685
- });
686
812
  const parentId = params.parentCtx.getAttribute(TRACE_SPAN_ATTRIBUTE);
687
813
  if (typeof parentId === "number") {
688
814
  this.parentId = parentId;
@@ -693,9 +819,17 @@ var TracingSpan = class _TracingSpan {
693
819
  const resource2 = this._traceProcessor.resources.get(this.resourceId);
694
820
  return resource2 ? `${resource2.sanitizedClassName}#${resource2.data.instanceId}.${this.methodName}` : this.methodName;
695
821
  }
822
+ /** Sanitized class name of the owning resource, if available. */
823
+ get sanitizedClassName() {
824
+ const resource2 = this.resourceId != null ? this._traceProcessor.resources.get(this.resourceId) : void 0;
825
+ return resource2?.sanitizedClassName;
826
+ }
696
827
  get ctx() {
697
828
  return this._ctx;
698
829
  }
830
+ get showInRemoteTracing() {
831
+ return this._showInRemoteTracing;
832
+ }
699
833
  markSuccess() {
700
834
  this.endTs = performance.now();
701
835
  this._traceProcessor._flushSpan(this);
@@ -802,13 +936,13 @@ var areEqualShallow = (a, b) => {
802
936
  return true;
803
937
  };
804
938
  var sanitizeClassName = (className) => {
939
+ let name = className.replace(/^_+/, "");
805
940
  const SANITIZE_REGEX = /[^_](\d+)$/;
806
- const m = className.match(SANITIZE_REGEX);
807
- if (!m) {
808
- return className;
809
- } else {
810
- return className.slice(0, -m[1].length);
941
+ const m = name.match(SANITIZE_REGEX);
942
+ if (m) {
943
+ name = name.slice(0, -m[1].length);
811
944
  }
945
+ return name;
812
946
  };
813
947
  var isSetLike = (value) => value instanceof Set || typeof value === "object" && value !== null && Object.getPrototypeOf(value).constructor.name === "ComplexSet";
814
948
  var isMapLike = (value) => value instanceof Map || typeof value === "object" && value !== null && Object.getPrototypeOf(value).constructor.name === "ComplexMap";
@@ -838,30 +972,33 @@ var info = (opts = {}) => (target, propertyKey, descriptor) => {
838
972
  var mark = (name) => {
839
973
  performance.mark(name);
840
974
  };
841
- var span = ({ showInBrowserTimeline = false, op, attributes } = {}) => (target, propertyKey, descriptor) => {
975
+ var span = ({ showInBrowserTimeline = false, showInRemoteTracing = true, op, attributes } = {}) => (target, propertyKey, descriptor) => {
842
976
  const method = descriptor.value;
843
977
  descriptor.value = async function(...args) {
844
- const parentCtx = args[0] instanceof Context2 ? args[0] : null;
978
+ const explicitCtx = args[0] instanceof Context3 ? args[0] : null;
845
979
  const span2 = TRACE_PROCESSOR.traceSpan({
846
- parentCtx,
980
+ parentCtx: explicitCtx,
847
981
  methodName: propertyKey,
848
982
  instance: this,
849
983
  showInBrowserTimeline,
984
+ showInRemoteTracing,
850
985
  op,
851
986
  attributes
852
987
  });
853
- const callArgs = span2.ctx ? [
988
+ const callArgs = explicitCtx ? [
854
989
  span2.ctx,
855
990
  ...args.slice(1)
856
991
  ] : args;
857
- try {
858
- return await method.apply(this, callArgs);
859
- } catch (err) {
860
- span2.markError(err);
861
- throw err;
862
- } finally {
863
- span2.markSuccess();
864
- }
992
+ return TRACE_PROCESSOR.remoteTracing.wrapExecution(span2, async () => {
993
+ try {
994
+ return await method.apply(this, callArgs);
995
+ } catch (err) {
996
+ span2.markError(err);
997
+ throw err;
998
+ } finally {
999
+ span2.markSuccess();
1000
+ }
1001
+ });
865
1002
  };
866
1003
  };
867
1004
  var spans = /* @__PURE__ */ new Map();
@@ -903,6 +1040,11 @@ var trace = {
903
1040
 
904
1041
  // src/metrics/base.ts
905
1042
  var BaseCounter = class {
1043
+ /**
1044
+ * @internal
1045
+ */
1046
+ _instance;
1047
+ name;
906
1048
  /**
907
1049
  * @internal
908
1050
  */
@@ -916,9 +1058,10 @@ var BaseCounter = class {
916
1058
 
917
1059
  // src/metrics/unary-counter.ts
918
1060
  var UnaryCounter = class extends BaseCounter {
1061
+ value = 0;
1062
+ units;
919
1063
  constructor({ units } = {}) {
920
1064
  super();
921
- this.value = 0;
922
1065
  this.units = units;
923
1066
  }
924
1067
  inc(by = 1) {
@@ -938,11 +1081,12 @@ var UnaryCounter = class extends BaseCounter {
938
1081
  // src/metrics/time-series-counter.ts
939
1082
  var MAX_BUCKETS = 60;
940
1083
  var TimeSeriesCounter = class extends BaseCounter {
1084
+ _currentValue = 0;
1085
+ _totalValue = 0;
1086
+ _buckets = [];
1087
+ units;
941
1088
  constructor({ units } = {}) {
942
1089
  super();
943
- this._currentValue = 0;
944
- this._totalValue = 0;
945
- this._buckets = [];
946
1090
  this.units = units;
947
1091
  }
948
1092
  inc(by = 1) {
@@ -978,13 +1122,10 @@ var TimeSeriesCounter = class extends BaseCounter {
978
1122
  // src/metrics/time-usage-counter.ts
979
1123
  var MAX_BUCKETS2 = 60;
980
1124
  var TimeUsageCounter = class extends BaseCounter {
981
- constructor() {
982
- super(...arguments);
983
- this._currentValue = 0;
984
- this._totalValue = 0;
985
- this._buckets = [];
986
- this._lastTickTime = performance.now();
987
- }
1125
+ _currentValue = 0;
1126
+ _totalValue = 0;
1127
+ _buckets = [];
1128
+ _lastTickTime = performance.now();
988
1129
  record(time) {
989
1130
  this._currentValue += time;
990
1131
  this._totalValue += time;
@@ -1029,9 +1170,10 @@ var TimeUsageCounter = class extends BaseCounter {
1029
1170
 
1030
1171
  // src/metrics/map-counter.ts
1031
1172
  var MapCounter = class extends BaseCounter {
1173
+ values = /* @__PURE__ */ new Map();
1174
+ units;
1032
1175
  constructor({ units } = {}) {
1033
1176
  super();
1034
- this.values = /* @__PURE__ */ new Map();
1035
1177
  this.units = units;
1036
1178
  }
1037
1179
  inc(key, by = 1) {
@@ -1054,6 +1196,7 @@ var MapCounter = class extends BaseCounter {
1054
1196
 
1055
1197
  // src/metrics/custom-counter.ts
1056
1198
  var CustomCounter = class extends BaseCounter {
1199
+ _getData;
1057
1200
  constructor(_getData) {
1058
1201
  super(), this._getData = _getData;
1059
1202
  }