@dxos/tracing 0.8.4-main.937b3ca → 0.8.4-main.9be5663bfe
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.
- package/dist/lib/browser/index.mjs +157 -36
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +157 -36
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/api.d.ts +3 -1
- package/dist/types/src/api.d.ts.map +1 -1
- package/dist/types/src/remote/tracing.d.ts +34 -0
- package/dist/types/src/remote/tracing.d.ts.map +1 -1
- package/dist/types/src/trace-processor.d.ts +7 -2
- package/dist/types/src/trace-processor.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/src/api.ts +19 -12
- package/src/remote/tracing.ts +133 -11
- package/src/trace-processor.ts +25 -13
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/api.ts
|
|
2
|
-
import { Context as
|
|
2
|
+
import { Context as Context3 } from "@dxos/context";
|
|
3
3
|
|
|
4
4
|
// src/symbols.ts
|
|
5
|
-
var symbolTracingContext = Symbol("dxos.tracing.context");
|
|
5
|
+
var symbolTracingContext = /* @__PURE__ */ Symbol("dxos.tracing.context");
|
|
6
6
|
var getTracingContext = (target) => {
|
|
7
7
|
return target[symbolTracingContext] ??= {
|
|
8
8
|
infoProperties: {},
|
|
@@ -13,6 +13,7 @@ var TRACE_SPAN_ATTRIBUTE = "dxos.trace-span";
|
|
|
13
13
|
|
|
14
14
|
// src/trace-processor.ts
|
|
15
15
|
import { unrefTimeout } from "@dxos/async";
|
|
16
|
+
import { Context as Context2 } from "@dxos/context";
|
|
16
17
|
import { LogLevel, getContextFromEntry, log } from "@dxos/log";
|
|
17
18
|
import { getPrototypeSpecificInstanceId } from "@dxos/util";
|
|
18
19
|
|
|
@@ -283,29 +284,132 @@ var RemoteMetrics = class {
|
|
|
283
284
|
};
|
|
284
285
|
|
|
285
286
|
// src/remote/tracing.ts
|
|
287
|
+
var MAX_ENDED_CONTEXTS = 1e4;
|
|
286
288
|
var RemoteTracing = class {
|
|
287
289
|
_tracing;
|
|
288
290
|
_spanMap = /* @__PURE__ */ new Map();
|
|
291
|
+
_idToSpan = /* @__PURE__ */ new Map();
|
|
292
|
+
/**
|
|
293
|
+
* Retains OTEL span contexts after spans end so that periodic/background
|
|
294
|
+
* operations referencing a completed parent (via `this._ctx`) still produce
|
|
295
|
+
* correlated child spans instead of orphaned root traces.
|
|
296
|
+
*/
|
|
297
|
+
_endedSpanContexts = /* @__PURE__ */ new Map();
|
|
298
|
+
/**
|
|
299
|
+
* Buffers flushSpan calls that arrive before a processor is registered,
|
|
300
|
+
* so early startup spans are not silently dropped.
|
|
301
|
+
*/
|
|
302
|
+
_pendingFlushes = [];
|
|
289
303
|
registerProcessor(processor) {
|
|
290
304
|
this._tracing = processor;
|
|
305
|
+
const pending = this._pendingFlushes;
|
|
306
|
+
this._pendingFlushes = null;
|
|
307
|
+
if (pending) {
|
|
308
|
+
for (const { span: span2, isEnd } of pending) {
|
|
309
|
+
this._replayFlush(span2, isEnd);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
/** Returns the opaque OTEL context for the given DXOS span ID, if one exists. */
|
|
314
|
+
getSpanContext(spanId) {
|
|
315
|
+
const tracingSpan = this._idToSpan.get(spanId);
|
|
316
|
+
if (tracingSpan) {
|
|
317
|
+
return this._spanMap.get(tracingSpan)?.spanContext;
|
|
318
|
+
}
|
|
319
|
+
return this._endedSpanContexts.get(spanId);
|
|
320
|
+
}
|
|
321
|
+
/** Wraps execution so that the remote span is active as parent context. */
|
|
322
|
+
wrapExecution(span2, fn) {
|
|
323
|
+
const remoteSpan = this._spanMap.get(span2);
|
|
324
|
+
if (remoteSpan?.wrapExecution) {
|
|
325
|
+
return remoteSpan.wrapExecution(fn);
|
|
326
|
+
}
|
|
327
|
+
return fn();
|
|
291
328
|
}
|
|
292
329
|
flushSpan(span2) {
|
|
330
|
+
if (!span2.showInRemoteTracing) {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
293
333
|
if (!this._tracing) {
|
|
334
|
+
this._pendingFlushes?.push({
|
|
335
|
+
span: span2,
|
|
336
|
+
isEnd: !!span2.endTs
|
|
337
|
+
});
|
|
294
338
|
return;
|
|
295
339
|
}
|
|
296
340
|
if (!span2.endTs) {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
341
|
+
this._startRemoteSpan(span2);
|
|
342
|
+
} else {
|
|
343
|
+
this._endRemoteSpan(span2);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
_startRemoteSpan(span2) {
|
|
347
|
+
let parentContext;
|
|
348
|
+
if (span2.parentId != null) {
|
|
349
|
+
const parentTracingSpan = this._idToSpan.get(span2.parentId);
|
|
350
|
+
if (parentTracingSpan) {
|
|
351
|
+
parentContext = this._spanMap.get(parentTracingSpan)?.spanContext;
|
|
352
|
+
}
|
|
353
|
+
if (parentContext == null) {
|
|
354
|
+
parentContext = this._endedSpanContexts.get(span2.parentId);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
const attributes = {};
|
|
358
|
+
if (span2.sanitizedClassName) {
|
|
359
|
+
attributes.entryPoint = span2.sanitizedClassName;
|
|
360
|
+
}
|
|
361
|
+
for (const [key, value] of Object.entries(span2.attributes)) {
|
|
362
|
+
attributes[key.startsWith("ctx.") ? key : `ctx.${key}`] = value;
|
|
363
|
+
}
|
|
364
|
+
const remoteSpan = this._tracing.startSpan({
|
|
365
|
+
name: span2.name,
|
|
366
|
+
op: span2.op ?? "function",
|
|
367
|
+
attributes,
|
|
368
|
+
parentContext
|
|
369
|
+
});
|
|
370
|
+
this._spanMap.set(span2, remoteSpan);
|
|
371
|
+
this._idToSpan.set(span2.id, span2);
|
|
372
|
+
}
|
|
373
|
+
_endRemoteSpan(span2) {
|
|
374
|
+
const remoteSpan = this._spanMap.get(span2);
|
|
375
|
+
if (remoteSpan) {
|
|
376
|
+
if (remoteSpan.spanContext != null) {
|
|
377
|
+
this._endedSpanContexts.set(span2.id, remoteSpan.spanContext);
|
|
378
|
+
this._evictEndedContexts();
|
|
379
|
+
}
|
|
380
|
+
remoteSpan.end();
|
|
381
|
+
this._spanMap.delete(span2);
|
|
382
|
+
this._idToSpan.delete(span2.id);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Replays a buffered flush that was queued before the processor was registered.
|
|
387
|
+
* For spans that started AND ended before registration, replays both events.
|
|
388
|
+
*/
|
|
389
|
+
_replayFlush(span2, isEnd) {
|
|
390
|
+
if (!isEnd) {
|
|
391
|
+
this._startRemoteSpan(span2);
|
|
392
|
+
if (span2.endTs != null) {
|
|
393
|
+
this._endRemoteSpan(span2);
|
|
394
|
+
}
|
|
303
395
|
} else {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
remoteSpan.end();
|
|
307
|
-
this._spanMap.delete(span2);
|
|
396
|
+
if (!this._spanMap.has(span2)) {
|
|
397
|
+
this._startRemoteSpan(span2);
|
|
308
398
|
}
|
|
399
|
+
this._endRemoteSpan(span2);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
_evictEndedContexts() {
|
|
403
|
+
if (this._endedSpanContexts.size <= MAX_ENDED_CONTEXTS) {
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
const iterator = this._endedSpanContexts.keys();
|
|
407
|
+
while (this._endedSpanContexts.size > MAX_ENDED_CONTEXTS) {
|
|
408
|
+
const oldest = iterator.next();
|
|
409
|
+
if (oldest.done) {
|
|
410
|
+
break;
|
|
411
|
+
}
|
|
412
|
+
this._endedSpanContexts.delete(oldest.value);
|
|
309
413
|
}
|
|
310
414
|
}
|
|
311
415
|
};
|
|
@@ -455,7 +559,7 @@ var TraceProcessor = class {
|
|
|
455
559
|
constructor() {
|
|
456
560
|
log.addProcessor(this._logProcessor.bind(this), void 0, {
|
|
457
561
|
F: __dxlog_file3,
|
|
458
|
-
L:
|
|
562
|
+
L: 104,
|
|
459
563
|
S: this,
|
|
460
564
|
C: (f, a) => f(...a)
|
|
461
565
|
});
|
|
@@ -681,7 +785,8 @@ var TracingSpan = class _TracingSpan {
|
|
|
681
785
|
endTs = null;
|
|
682
786
|
error = null;
|
|
683
787
|
_showInBrowserTimeline;
|
|
684
|
-
|
|
788
|
+
_showInRemoteTracing;
|
|
789
|
+
_ctx;
|
|
685
790
|
constructor(_traceProcessor, params) {
|
|
686
791
|
this._traceProcessor = _traceProcessor;
|
|
687
792
|
this.id = _TracingSpan.nextId++;
|
|
@@ -689,14 +794,19 @@ var TracingSpan = class _TracingSpan {
|
|
|
689
794
|
this.resourceId = _traceProcessor.getResourceId(params.instance);
|
|
690
795
|
this.startTs = performance.now();
|
|
691
796
|
this._showInBrowserTimeline = params.showInBrowserTimeline;
|
|
797
|
+
this._showInRemoteTracing = params.showInRemoteTracing ?? true;
|
|
692
798
|
this.op = params.op;
|
|
693
799
|
this.attributes = params.attributes ?? {};
|
|
800
|
+
const baseCtx = params.parentCtx ?? new Context2(void 0, {
|
|
801
|
+
F: __dxlog_file3,
|
|
802
|
+
L: 397
|
|
803
|
+
});
|
|
804
|
+
this._ctx = this._showInRemoteTracing ? baseCtx.derive({
|
|
805
|
+
attributes: {
|
|
806
|
+
[TRACE_SPAN_ATTRIBUTE]: this.id
|
|
807
|
+
}
|
|
808
|
+
}) : baseCtx.derive();
|
|
694
809
|
if (params.parentCtx) {
|
|
695
|
-
this._ctx = params.parentCtx.derive({
|
|
696
|
-
attributes: {
|
|
697
|
-
[TRACE_SPAN_ATTRIBUTE]: this.id
|
|
698
|
-
}
|
|
699
|
-
});
|
|
700
810
|
const parentId = params.parentCtx.getAttribute(TRACE_SPAN_ATTRIBUTE);
|
|
701
811
|
if (typeof parentId === "number") {
|
|
702
812
|
this.parentId = parentId;
|
|
@@ -707,9 +817,17 @@ var TracingSpan = class _TracingSpan {
|
|
|
707
817
|
const resource2 = this._traceProcessor.resources.get(this.resourceId);
|
|
708
818
|
return resource2 ? `${resource2.sanitizedClassName}#${resource2.data.instanceId}.${this.methodName}` : this.methodName;
|
|
709
819
|
}
|
|
820
|
+
/** Sanitized class name of the owning resource, if available. */
|
|
821
|
+
get sanitizedClassName() {
|
|
822
|
+
const resource2 = this.resourceId != null ? this._traceProcessor.resources.get(this.resourceId) : void 0;
|
|
823
|
+
return resource2?.sanitizedClassName;
|
|
824
|
+
}
|
|
710
825
|
get ctx() {
|
|
711
826
|
return this._ctx;
|
|
712
827
|
}
|
|
828
|
+
get showInRemoteTracing() {
|
|
829
|
+
return this._showInRemoteTracing;
|
|
830
|
+
}
|
|
713
831
|
markSuccess() {
|
|
714
832
|
this.endTs = performance.now();
|
|
715
833
|
this._traceProcessor._flushSpan(this);
|
|
@@ -816,13 +934,13 @@ var areEqualShallow = (a, b) => {
|
|
|
816
934
|
return true;
|
|
817
935
|
};
|
|
818
936
|
var sanitizeClassName = (className) => {
|
|
937
|
+
let name = className.replace(/^_+/, "");
|
|
819
938
|
const SANITIZE_REGEX = /[^_](\d+)$/;
|
|
820
|
-
const m =
|
|
821
|
-
if (
|
|
822
|
-
|
|
823
|
-
} else {
|
|
824
|
-
return className.slice(0, -m[1].length);
|
|
939
|
+
const m = name.match(SANITIZE_REGEX);
|
|
940
|
+
if (m) {
|
|
941
|
+
name = name.slice(0, -m[1].length);
|
|
825
942
|
}
|
|
943
|
+
return name;
|
|
826
944
|
};
|
|
827
945
|
var isSetLike = (value) => value instanceof Set || typeof value === "object" && value !== null && Object.getPrototypeOf(value).constructor.name === "ComplexSet";
|
|
828
946
|
var isMapLike = (value) => value instanceof Map || typeof value === "object" && value !== null && Object.getPrototypeOf(value).constructor.name === "ComplexMap";
|
|
@@ -852,30 +970,33 @@ var info = (opts = {}) => (target, propertyKey, descriptor) => {
|
|
|
852
970
|
var mark = (name) => {
|
|
853
971
|
performance.mark(name);
|
|
854
972
|
};
|
|
855
|
-
var span = ({ showInBrowserTimeline = false, op, attributes } = {}) => (target, propertyKey, descriptor) => {
|
|
973
|
+
var span = ({ showInBrowserTimeline = false, showInRemoteTracing = true, op, attributes } = {}) => (target, propertyKey, descriptor) => {
|
|
856
974
|
const method = descriptor.value;
|
|
857
975
|
descriptor.value = async function(...args) {
|
|
858
|
-
const
|
|
976
|
+
const explicitCtx = args[0] instanceof Context3 ? args[0] : null;
|
|
859
977
|
const span2 = TRACE_PROCESSOR.traceSpan({
|
|
860
|
-
parentCtx,
|
|
978
|
+
parentCtx: explicitCtx,
|
|
861
979
|
methodName: propertyKey,
|
|
862
980
|
instance: this,
|
|
863
981
|
showInBrowserTimeline,
|
|
982
|
+
showInRemoteTracing,
|
|
864
983
|
op,
|
|
865
984
|
attributes
|
|
866
985
|
});
|
|
867
|
-
const callArgs =
|
|
986
|
+
const callArgs = explicitCtx ? [
|
|
868
987
|
span2.ctx,
|
|
869
988
|
...args.slice(1)
|
|
870
989
|
] : args;
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
990
|
+
return TRACE_PROCESSOR.remoteTracing.wrapExecution(span2, async () => {
|
|
991
|
+
try {
|
|
992
|
+
return await method.apply(this, callArgs);
|
|
993
|
+
} catch (err) {
|
|
994
|
+
span2.markError(err);
|
|
995
|
+
throw err;
|
|
996
|
+
} finally {
|
|
997
|
+
span2.markSuccess();
|
|
998
|
+
}
|
|
999
|
+
});
|
|
879
1000
|
};
|
|
880
1001
|
};
|
|
881
1002
|
var spans = /* @__PURE__ */ new Map();
|