@dxos/tracing 0.8.4-main.bc674ce → 0.8.4-main.bd9b33e6c8

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
 
@@ -285,29 +286,132 @@ var RemoteMetrics = class {
285
286
  };
286
287
 
287
288
  // src/remote/tracing.ts
289
+ var MAX_ENDED_CONTEXTS = 1e4;
288
290
  var RemoteTracing = class {
289
291
  _tracing;
290
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 = [];
291
305
  registerProcessor(processor) {
292
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();
293
330
  }
294
331
  flushSpan(span2) {
332
+ if (!span2.showInRemoteTracing) {
333
+ return;
334
+ }
295
335
  if (!this._tracing) {
336
+ this._pendingFlushes?.push({
337
+ span: span2,
338
+ isEnd: !!span2.endTs
339
+ });
296
340
  return;
297
341
  }
298
342
  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);
343
+ this._startRemoteSpan(span2);
344
+ } else {
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
+ }
305
397
  } else {
306
- const remoteSpan = this._spanMap.get(span2);
307
- if (remoteSpan) {
308
- remoteSpan.end();
309
- this._spanMap.delete(span2);
398
+ if (!this._spanMap.has(span2)) {
399
+ this._startRemoteSpan(span2);
310
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;
413
+ }
414
+ this._endedSpanContexts.delete(oldest.value);
311
415
  }
312
416
  }
313
417
  };
@@ -457,7 +561,7 @@ var TraceProcessor = class {
457
561
  constructor() {
458
562
  log.addProcessor(this._logProcessor.bind(this), void 0, {
459
563
  F: __dxlog_file3,
460
- L: 103,
564
+ L: 104,
461
565
  S: this,
462
566
  C: (f, a) => f(...a)
463
567
  });
@@ -683,7 +787,8 @@ var TracingSpan = class _TracingSpan {
683
787
  endTs = null;
684
788
  error = null;
685
789
  _showInBrowserTimeline;
686
- _ctx = null;
790
+ _showInRemoteTracing;
791
+ _ctx;
687
792
  constructor(_traceProcessor, params) {
688
793
  this._traceProcessor = _traceProcessor;
689
794
  this.id = _TracingSpan.nextId++;
@@ -691,14 +796,19 @@ var TracingSpan = class _TracingSpan {
691
796
  this.resourceId = _traceProcessor.getResourceId(params.instance);
692
797
  this.startTs = performance.now();
693
798
  this._showInBrowserTimeline = params.showInBrowserTimeline;
799
+ this._showInRemoteTracing = params.showInRemoteTracing ?? true;
694
800
  this.op = params.op;
695
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();
696
811
  if (params.parentCtx) {
697
- this._ctx = params.parentCtx.derive({
698
- attributes: {
699
- [TRACE_SPAN_ATTRIBUTE]: this.id
700
- }
701
- });
702
812
  const parentId = params.parentCtx.getAttribute(TRACE_SPAN_ATTRIBUTE);
703
813
  if (typeof parentId === "number") {
704
814
  this.parentId = parentId;
@@ -709,9 +819,17 @@ var TracingSpan = class _TracingSpan {
709
819
  const resource2 = this._traceProcessor.resources.get(this.resourceId);
710
820
  return resource2 ? `${resource2.sanitizedClassName}#${resource2.data.instanceId}.${this.methodName}` : this.methodName;
711
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
+ }
712
827
  get ctx() {
713
828
  return this._ctx;
714
829
  }
830
+ get showInRemoteTracing() {
831
+ return this._showInRemoteTracing;
832
+ }
715
833
  markSuccess() {
716
834
  this.endTs = performance.now();
717
835
  this._traceProcessor._flushSpan(this);
@@ -818,13 +936,13 @@ var areEqualShallow = (a, b) => {
818
936
  return true;
819
937
  };
820
938
  var sanitizeClassName = (className) => {
939
+ let name = className.replace(/^_+/, "");
821
940
  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);
941
+ const m = name.match(SANITIZE_REGEX);
942
+ if (m) {
943
+ name = name.slice(0, -m[1].length);
827
944
  }
945
+ return name;
828
946
  };
829
947
  var isSetLike = (value) => value instanceof Set || typeof value === "object" && value !== null && Object.getPrototypeOf(value).constructor.name === "ComplexSet";
830
948
  var isMapLike = (value) => value instanceof Map || typeof value === "object" && value !== null && Object.getPrototypeOf(value).constructor.name === "ComplexMap";
@@ -854,30 +972,33 @@ var info = (opts = {}) => (target, propertyKey, descriptor) => {
854
972
  var mark = (name) => {
855
973
  performance.mark(name);
856
974
  };
857
- var span = ({ showInBrowserTimeline = false, op, attributes } = {}) => (target, propertyKey, descriptor) => {
975
+ var span = ({ showInBrowserTimeline = false, showInRemoteTracing = true, op, attributes } = {}) => (target, propertyKey, descriptor) => {
858
976
  const method = descriptor.value;
859
977
  descriptor.value = async function(...args) {
860
- const parentCtx = args[0] instanceof Context2 ? args[0] : null;
978
+ const explicitCtx = args[0] instanceof Context3 ? args[0] : null;
861
979
  const span2 = TRACE_PROCESSOR.traceSpan({
862
- parentCtx,
980
+ parentCtx: explicitCtx,
863
981
  methodName: propertyKey,
864
982
  instance: this,
865
983
  showInBrowserTimeline,
984
+ showInRemoteTracing,
866
985
  op,
867
986
  attributes
868
987
  });
869
- const callArgs = span2.ctx ? [
988
+ const callArgs = explicitCtx ? [
870
989
  span2.ctx,
871
990
  ...args.slice(1)
872
991
  ] : args;
873
- try {
874
- return await method.apply(this, callArgs);
875
- } catch (err) {
876
- span2.markError(err);
877
- throw err;
878
- } finally {
879
- span2.markSuccess();
880
- }
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
+ });
881
1002
  };
882
1003
  };
883
1004
  var spans = /* @__PURE__ */ new Map();