@dxos/tracing 0.8.3 → 0.8.4-main.05e74ebcff

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 (51) hide show
  1. package/LICENSE +102 -5
  2. package/dist/lib/browser/index.mjs +416 -456
  3. package/dist/lib/browser/index.mjs.map +4 -4
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/node-esm/index.mjs +416 -456
  6. package/dist/lib/node-esm/index.mjs.map +4 -4
  7. package/dist/lib/node-esm/meta.json +1 -1
  8. package/dist/types/src/api.d.ts +36 -17
  9. package/dist/types/src/api.d.ts.map +1 -1
  10. package/dist/types/src/buffering-backend.d.ts +24 -0
  11. package/dist/types/src/buffering-backend.d.ts.map +1 -0
  12. package/dist/types/src/diagnostic.d.ts +2 -2
  13. package/dist/types/src/diagnostic.d.ts.map +1 -1
  14. package/dist/types/src/diagnostics-channel.d.ts.map +1 -1
  15. package/dist/types/src/index.d.ts +1 -2
  16. package/dist/types/src/index.d.ts.map +1 -1
  17. package/dist/types/src/metrics/base.d.ts.map +1 -1
  18. package/dist/types/src/metrics/custom-counter.d.ts.map +1 -1
  19. package/dist/types/src/metrics/map-counter.d.ts.map +1 -1
  20. package/dist/types/src/metrics/time-series-counter.d.ts.map +1 -1
  21. package/dist/types/src/metrics/time-usage-counter.d.ts.map +1 -1
  22. package/dist/types/src/metrics/unary-counter.d.ts.map +1 -1
  23. package/dist/types/src/remote/index.d.ts +0 -1
  24. package/dist/types/src/remote/index.d.ts.map +1 -1
  25. package/dist/types/src/remote/metrics.d.ts.map +1 -1
  26. package/dist/types/src/symbols.d.ts +0 -1
  27. package/dist/types/src/symbols.d.ts.map +1 -1
  28. package/dist/types/src/trace-processor.d.ts +16 -52
  29. package/dist/types/src/trace-processor.d.ts.map +1 -1
  30. package/dist/types/src/tracing-types.d.ts +67 -0
  31. package/dist/types/src/tracing-types.d.ts.map +1 -0
  32. package/dist/types/tsconfig.tsbuildinfo +1 -1
  33. package/package.json +16 -15
  34. package/src/api.ts +237 -35
  35. package/src/buffering-backend.ts +112 -0
  36. package/src/diagnostic.ts +2 -2
  37. package/src/index.ts +1 -2
  38. package/src/remote/index.ts +0 -1
  39. package/src/symbols.ts +0 -2
  40. package/src/trace-processor.ts +59 -259
  41. package/src/tracing-types.ts +77 -0
  42. package/src/tracing.test.ts +513 -4
  43. package/dist/lib/node/index.cjs +0 -1111
  44. package/dist/lib/node/index.cjs.map +0 -7
  45. package/dist/lib/node/meta.json +0 -1
  46. package/dist/types/src/remote/tracing.d.ts +0 -23
  47. package/dist/types/src/remote/tracing.d.ts.map +0 -1
  48. package/dist/types/src/trace-sender.d.ts +0 -9
  49. package/dist/types/src/trace-sender.d.ts.map +0 -1
  50. package/src/remote/tracing.ts +0 -53
  51. package/src/trace-sender.ts +0 -88
@@ -1,34 +1,122 @@
1
1
  import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
2
 
3
- // packages/common/tracing/src/api.ts
4
- import { Context as Context2 } from "@dxos/context";
3
+ // src/api.ts
4
+ import { Context as Context2, LifecycleState, Resource, TRACE_SPAN_ATTRIBUTE } from "@dxos/context";
5
5
 
6
- // packages/common/tracing/src/symbols.ts
7
- var symbolTracingContext = Symbol("dxos.tracing.context");
6
+ // src/symbols.ts
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
- // packages/common/tracing/src/trace-processor.ts
17
- import { unrefTimeout } from "@dxos/async";
18
- import { LogLevel, getContextFromEntry, log } from "@dxos/log";
15
+ // src/trace-processor.ts
16
+ import { LogLevel, log } from "@dxos/log";
19
17
  import { getPrototypeSpecificInstanceId } from "@dxos/util";
20
18
 
21
- // packages/common/tracing/src/diagnostic.ts
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
+
105
+ // src/diagnostic.ts
22
106
  import { asyncTimeout } from "@dxos/async";
23
107
  import { invariant } from "@dxos/invariant";
24
108
 
25
- // packages/common/tracing/src/util.ts
109
+ // src/util.ts
26
110
  var createId = () => Math.random().toString(36).slice(2);
27
111
 
28
- // packages/common/tracing/src/diagnostic.ts
29
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/common/tracing/src/diagnostic.ts";
112
+ // src/diagnostic.ts
113
+ var __dxlog_file = "/__w/dxos/dxos/packages/common/tracing/src/diagnostic.ts";
30
114
  var DIAGNOSTICS_TIMEOUT = 1e4;
31
115
  var TraceDiagnosticImpl = class {
116
+ id;
117
+ fetch;
118
+ name;
119
+ _onUnregister;
32
120
  constructor(id, fetch, name, _onUnregister) {
33
121
  this.id = id;
34
122
  this.fetch = fetch;
@@ -40,11 +128,9 @@ var TraceDiagnosticImpl = class {
40
128
  }
41
129
  };
42
130
  var DiagnosticsManager = class {
43
- constructor() {
44
- this.instanceId = createId();
45
- this.registry = /* @__PURE__ */ new Map();
46
- this._instanceTag = null;
47
- }
131
+ instanceId = createId();
132
+ registry = /* @__PURE__ */ new Map();
133
+ _instanceTag = null;
48
134
  get instanceTag() {
49
135
  return this._instanceTag;
50
136
  }
@@ -70,27 +156,11 @@ var DiagnosticsManager = class {
70
156
  }
71
157
  async fetch(request) {
72
158
  if (request.instanceId != null) {
73
- invariant(request.instanceId === this.instanceId, "Invalid instance id", {
74
- F: __dxlog_file,
75
- L: 82,
76
- S: this,
77
- A: [
78
- "request.instanceId === this.instanceId",
79
- "'Invalid instance id'"
80
- ]
81
- });
159
+ invariant(request.instanceId === this.instanceId, "Invalid instance id", { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 52, S: this, A: ["request.instanceId === this.instanceId", "'Invalid instance id'"] });
82
160
  }
83
161
  const { id } = request;
84
162
  const diagnostic2 = this.registry.get(id);
85
- invariant(diagnostic2, "Diagnostic not found", {
86
- F: __dxlog_file,
87
- L: 86,
88
- S: this,
89
- A: [
90
- "diagnostic",
91
- "'Diagnostic not found'"
92
- ]
93
- });
163
+ invariant(diagnostic2, "Diagnostic not found", { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 56, S: this, A: ["diagnostic", "'Diagnostic not found'"] });
94
164
  try {
95
165
  const data = await asyncTimeout(diagnostic2.fetch(), DIAGNOSTICS_TIMEOUT);
96
166
  return {
@@ -109,25 +179,24 @@ var DiagnosticsManager = class {
109
179
  }
110
180
  };
111
181
 
112
- // packages/common/tracing/src/diagnostics-channel.ts
182
+ // src/diagnostics-channel.ts
113
183
  import { Trigger, sleep } from "@dxos/async";
114
184
  import { Context } from "@dxos/context";
115
185
  import { invariant as invariant2 } from "@dxos/invariant";
116
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/common/tracing/src/diagnostics-channel.ts";
186
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/common/tracing/src/diagnostics-channel.ts";
117
187
  var DEFAULT_CHANNEL_NAME = "dxos-diagnostics";
118
188
  var DISCOVER_TIME = 500;
119
189
  var DiagnosticsChannel = class _DiagnosticsChannel {
190
+ _channelName;
120
191
  static get supported() {
121
192
  return globalThis.BroadcastChannel != null;
122
193
  }
194
+ _ctx = new Context(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 16 });
195
+ // Separate channels becauase the client and server may be in the same process.
196
+ _serveChannel = void 0;
197
+ _clientChannel = void 0;
123
198
  constructor(_channelName = DEFAULT_CHANNEL_NAME) {
124
199
  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
200
  if (_DiagnosticsChannel.supported) {
132
201
  this._serveChannel = new BroadcastChannel(_channelName);
133
202
  this._clientChannel = new BroadcastChannel(_channelName);
@@ -150,15 +219,7 @@ var DiagnosticsChannel = class _DiagnosticsChannel {
150
219
  }
151
220
  }
152
221
  serve(manager) {
153
- invariant2(this._serveChannel, void 0, {
154
- F: __dxlog_file2,
155
- L: 78,
156
- S: this,
157
- A: [
158
- "this._serveChannel",
159
- ""
160
- ]
161
- });
222
+ invariant2(this._serveChannel, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 43, S: this, A: ["this._serveChannel", ""] });
162
223
  const listener = async (event) => {
163
224
  switch (event.data.type) {
164
225
  case "DIAGNOSTICS_DISCOVER": {
@@ -190,15 +251,7 @@ var DiagnosticsChannel = class _DiagnosticsChannel {
190
251
  this._ctx.onDispose(() => this._serveChannel.removeEventListener("message", listener));
191
252
  }
192
253
  async discover() {
193
- invariant2(this._clientChannel, void 0, {
194
- F: __dxlog_file2,
195
- L: 114,
196
- S: this,
197
- A: [
198
- "this._clientChannel",
199
- ""
200
- ]
201
- });
254
+ invariant2(this._clientChannel, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 77, S: this, A: ["this._clientChannel", ""] });
202
255
  const diagnostics = [];
203
256
  const collector = (event) => {
204
257
  const data = event.data;
@@ -226,15 +279,7 @@ var DiagnosticsChannel = class _DiagnosticsChannel {
226
279
  }
227
280
  }
228
281
  async fetch(request) {
229
- invariant2(this._clientChannel, void 0, {
230
- F: __dxlog_file2,
231
- L: 147,
232
- S: this,
233
- A: [
234
- "this._clientChannel",
235
- ""
236
- ]
237
- });
282
+ invariant2(this._clientChannel, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 106, S: this, A: ["this._clientChannel", ""] });
238
283
  const requestId = createId();
239
284
  const trigger = new Trigger();
240
285
  const listener = (event) => {
@@ -260,11 +305,9 @@ var DiagnosticsChannel = class _DiagnosticsChannel {
260
305
  }
261
306
  };
262
307
 
263
- // packages/common/tracing/src/remote/metrics.ts
308
+ // src/remote/metrics.ts
264
309
  var RemoteMetrics = class {
265
- constructor() {
266
- this._metrics = /* @__PURE__ */ new Set();
267
- }
310
+ _metrics = /* @__PURE__ */ new Set();
268
311
  registerProcessor(processor) {
269
312
  this._metrics.add(processor);
270
313
  }
@@ -282,125 +325,7 @@ var RemoteMetrics = class {
282
325
  }
283
326
  };
284
327
 
285
- // packages/common/tracing/src/remote/tracing.ts
286
- var RemoteTracing = class {
287
- constructor() {
288
- this._spanMap = /* @__PURE__ */ new Map();
289
- }
290
- registerProcessor(processor) {
291
- this._tracing = processor;
292
- }
293
- flushSpan(span2) {
294
- if (!this._tracing) {
295
- return;
296
- }
297
- 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);
304
- } else {
305
- const remoteSpan = this._spanMap.get(span2);
306
- if (remoteSpan) {
307
- remoteSpan.end();
308
- this._spanMap.delete(span2);
309
- }
310
- }
311
- }
312
- };
313
-
314
- // packages/common/tracing/src/trace-sender.ts
315
- import { Stream } from "@dxos/codec-protobuf/stream";
316
- var TraceSender = class {
317
- constructor(_traceProcessor) {
318
- this._traceProcessor = _traceProcessor;
319
- }
320
- streamTrace(request) {
321
- return new Stream(({ ctx, next }) => {
322
- const flushEvents = (resources, spans2, logs) => {
323
- const event = {
324
- resourceAdded: [],
325
- resourceRemoved: [],
326
- spanAdded: [],
327
- logAdded: []
328
- };
329
- if (resources) {
330
- for (const id of resources) {
331
- const entry = this._traceProcessor.resources.get(id);
332
- if (entry) {
333
- event.resourceAdded.push({
334
- resource: entry.data
335
- });
336
- } else {
337
- event.resourceRemoved.push({
338
- id
339
- });
340
- }
341
- }
342
- } else {
343
- for (const entry of this._traceProcessor.resources.values()) {
344
- event.resourceAdded.push({
345
- resource: entry.data
346
- });
347
- }
348
- }
349
- if (spans2) {
350
- for (const id of spans2) {
351
- const span2 = this._traceProcessor.spans.get(id);
352
- if (span2) {
353
- event.spanAdded.push({
354
- span: span2
355
- });
356
- }
357
- }
358
- } else {
359
- for (const span2 of this._traceProcessor.spans.values()) {
360
- event.spanAdded.push({
361
- span: span2
362
- });
363
- }
364
- }
365
- if (logs) {
366
- for (const log2 of logs) {
367
- event.logAdded.push({
368
- log: log2
369
- });
370
- }
371
- } else {
372
- for (const log2 of this._traceProcessor.logs) {
373
- event.logAdded.push({
374
- log: log2
375
- });
376
- }
377
- }
378
- if (event.resourceAdded.length > 0 || event.resourceRemoved.length > 0 || event.spanAdded.length > 0) {
379
- next(event);
380
- }
381
- };
382
- const flush = () => {
383
- flushEvents(subscription.dirtyResources, subscription.dirtySpans, subscription.newLogs);
384
- subscription.dirtyResources.clear();
385
- subscription.dirtySpans.clear();
386
- subscription.newLogs.length = 0;
387
- };
388
- const subscription = {
389
- flush,
390
- dirtyResources: /* @__PURE__ */ new Set(),
391
- dirtySpans: /* @__PURE__ */ new Set(),
392
- newLogs: []
393
- };
394
- this._traceProcessor.subscriptions.add(subscription);
395
- ctx.onDispose(() => {
396
- this._traceProcessor.subscriptions.delete(subscription);
397
- });
398
- flushEvents(null, null, null);
399
- });
400
- }
401
- };
402
-
403
- // packages/common/tracing/src/weak-ref.ts
328
+ // src/weak-ref.ts
404
329
  var WeakRefMock = class {
405
330
  // eslint-disable-next-line @typescript-eslint/no-useless-constructor
406
331
  constructor(target) {
@@ -411,9 +336,18 @@ var WeakRefMock = class {
411
336
  };
412
337
  var WeakRef = globalThis.WeakRef ?? WeakRefMock;
413
338
 
414
- // packages/common/tracing/src/trace-processor.ts
415
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/common/tracing/src/trace-processor.ts";
339
+ // src/trace-processor.ts
340
+ var __dxlog_file3 = "/__w/dxos/dxos/packages/common/tracing/src/trace-processor.ts";
416
341
  var ResourceEntry = class {
342
+ data;
343
+ instance;
344
+ annotation;
345
+ /**
346
+ * Sometimes bundlers mangle class names: WebFile -> WebFile2.
347
+ *
348
+ * We use a heuristic to remove the suffix.
349
+ */
350
+ sanitizedClassName;
417
351
  constructor(data, instance, annotation) {
418
352
  this.data = data;
419
353
  this.instance = instance;
@@ -425,66 +359,56 @@ var ResourceEntry = class {
425
359
  }
426
360
  };
427
361
  var MAX_RESOURCE_RECORDS = 2e3;
428
- var MAX_SPAN_RECORDS = 1e3;
429
362
  var MAX_LOG_RECORDS = 1e3;
430
- var REFRESH_INTERVAL = 1e3;
431
363
  var MAX_INFO_OBJECT_DEPTH = 8;
432
- var IS_CLOUDFLARE_WORKERS = !!globalThis?.navigator?.userAgent?.includes("Cloudflare-Workers");
433
364
  var TraceProcessor = class {
434
- 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);
365
+ diagnostics = new DiagnosticsManager();
366
+ diagnosticsChannel = new DiagnosticsChannel();
367
+ remoteMetrics = new RemoteMetrics();
368
+ #bufferingBackend = new BufferingTracingBackend();
369
+ #activeBackend = this.#bufferingBackend;
370
+ /**
371
+ * Tracing backend. Initially a buffering backend that records spans;
372
+ * once the observability package sets a real backend, the buffer is drained
373
+ * and a thin translating wrapper is installed that resolves stale buffered
374
+ * parent IDs still held by in-flight {@link Context} objects.
375
+ *
376
+ * The wrapper only allocates when a `buffered-*` parent is actually encountered;
377
+ * the common path is a single `startsWith` check and direct passthrough.
378
+ */
379
+ get tracingBackend() {
380
+ return this.#activeBackend;
381
+ }
382
+ set tracingBackend(backend) {
383
+ if (!backend || backend === this.#bufferingBackend) {
384
+ this.#bufferingBackend.clear();
385
+ this.#activeBackend = this.#bufferingBackend;
386
+ return;
387
+ }
388
+ const idMap = this.#bufferingBackend.drain(backend);
389
+ this.#activeBackend = {
390
+ startSpan: (options) => {
391
+ const parent = options.parentContext;
392
+ if (parent?.traceparent.startsWith(BUFFERED_PREFIX)) {
393
+ const translated = idMap.get(parent.traceparent);
394
+ if (translated) {
395
+ return backend.startSpan({
396
+ ...options,
397
+ parentContext: translated
398
+ });
460
399
  }
461
- const entryToPush = {
462
- level: entry.level,
463
- message: entry.message,
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
400
  }
475
- default:
401
+ return backend.startSpan(options);
476
402
  }
477
403
  };
478
- log.addProcessor(this._logProcessor.bind(this), void 0, {
479
- F: __dxlog_file3,
480
- L: 103,
481
- S: this,
482
- C: (f, a) => f(...a)
483
- });
484
- if (!IS_CLOUDFLARE_WORKERS) {
485
- const refreshInterval = setInterval(this.refresh.bind(this), REFRESH_INTERVAL);
486
- unrefTimeout(refreshInterval);
487
- }
404
+ }
405
+ resources = /* @__PURE__ */ new Map();
406
+ resourceInstanceIndex = /* @__PURE__ */ new WeakMap();
407
+ resourceIdList = [];
408
+ logs = [];
409
+ _instanceTag = null;
410
+ constructor() {
411
+ log.addProcessor(this._logProcessor.bind(this), void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 80, S: this });
488
412
  if (DiagnosticsChannel.supported) {
489
413
  this.diagnosticsChannel.serve(this.diagnostics);
490
414
  }
@@ -494,10 +418,7 @@ var TraceProcessor = class {
494
418
  this._instanceTag = tag;
495
419
  this.diagnostics.setInstanceTag(tag);
496
420
  }
497
- /**
498
- * @internal
499
- */
500
- // TODO(burdon): Comment.
421
+ /** @internal */
501
422
  createTraceResource(params) {
502
423
  const id = this.resources.size;
503
424
  const tracingContext = getTracingContext(Object.getPrototypeOf(params.instance));
@@ -518,24 +439,10 @@ var TraceProcessor = class {
518
439
  if (this.resourceIdList.length > MAX_RESOURCE_RECORDS) {
519
440
  this._clearResources();
520
441
  }
521
- this._markResourceDirty(id);
522
- }
523
- createTraceSender() {
524
- return new TraceSender(this);
525
- }
526
- traceSpan(params) {
527
- const span2 = new TracingSpan(this, params);
528
- this._flushSpan(span2);
529
- return span2;
530
442
  }
531
443
  // TODO(burdon): Not implemented.
532
444
  addLink(parent, child, opts) {
533
445
  }
534
- //
535
- // Getters
536
- //
537
- // TODO(burdon): Define type.
538
- // TODO(burdon): Reconcile with system service.
539
446
  getDiagnostics() {
540
447
  this.refresh();
541
448
  return {
@@ -543,7 +450,6 @@ var TraceProcessor = class {
543
450
  `${entry.sanitizedClassName}#${entry.data.instanceId}`,
544
451
  entry.data
545
452
  ])),
546
- spans: Array.from(this.spans.values()),
547
453
  logs: this.logs.filter((log2) => log2.level >= LogLevel.INFO)
548
454
  };
549
455
  }
@@ -598,43 +504,8 @@ var TraceProcessor = class {
598
504
  for (const key of Object.keys(tracingContext.metricsProperties)) {
599
505
  instance[key]._tick?.(time);
600
506
  }
601
- let _changed = false;
602
- const oldInfo = resource2.data.info;
603
507
  resource2.data.info = this.getResourceInfo(instance);
604
- _changed ||= !areEqualShallow(oldInfo, resource2.data.info);
605
- const oldMetrics = resource2.data.metrics;
606
508
  resource2.data.metrics = this.getResourceMetrics(instance);
607
- _changed ||= !areEqualShallow(oldMetrics, resource2.data.metrics);
608
- this._markResourceDirty(resource2.data.id);
609
- }
610
- for (const subscription of this.subscriptions) {
611
- subscription.flush();
612
- }
613
- }
614
- //
615
- // Implementation
616
- //
617
- /**
618
- * @internal
619
- */
620
- _flushSpan(runtimeSpan) {
621
- const span2 = runtimeSpan.serialize();
622
- this.spans.set(span2.id, span2);
623
- this.spanIdList.push(span2.id);
624
- if (this.spanIdList.length > MAX_SPAN_RECORDS) {
625
- this._clearSpans();
626
- }
627
- this._markSpanDirty(span2.id);
628
- this.remoteTracing.flushSpan(runtimeSpan);
629
- }
630
- _markResourceDirty(id) {
631
- for (const subscription of this.subscriptions) {
632
- subscription.dirtyResources.add(id);
633
- }
634
- }
635
- _markSpanDirty(id) {
636
- for (const subscription of this.subscriptions) {
637
- subscription.dirtySpans.add(id);
638
509
  }
639
510
  }
640
511
  _clearResources() {
@@ -643,103 +514,45 @@ var TraceProcessor = class {
643
514
  this.resources.delete(id);
644
515
  }
645
516
  }
646
- _clearSpans() {
647
- while (this.spanIdList.length > MAX_SPAN_RECORDS) {
648
- const id = this.spanIdList.shift();
649
- this.spans.delete(id);
650
- }
651
- }
652
517
  _pushLog(log2) {
653
518
  this.logs.push(log2);
654
519
  if (this.logs.length > MAX_LOG_RECORDS) {
655
520
  this.logs.shift();
656
521
  }
657
- for (const subscription of this.subscriptions) {
658
- subscription.newLogs.push(log2);
659
- }
660
522
  }
661
- };
662
- var TracingSpan = class _TracingSpan {
663
- static {
664
- this.nextId = 0;
665
- }
666
- constructor(_traceProcessor, params) {
667
- this._traceProcessor = _traceProcessor;
668
- this.parentId = null;
669
- this.resourceId = null;
670
- this.endTs = null;
671
- this.error = null;
672
- this._ctx = null;
673
- this.id = _TracingSpan.nextId++;
674
- this.methodName = params.methodName;
675
- this.resourceId = _traceProcessor.getResourceId(params.instance);
676
- this.startTs = performance.now();
677
- this._showInBrowserTimeline = params.showInBrowserTimeline;
678
- this.op = params.op;
679
- this.attributes = params.attributes ?? {};
680
- if (params.parentCtx) {
681
- this._ctx = params.parentCtx.derive({
682
- attributes: {
683
- [TRACE_SPAN_ATTRIBUTE]: this.id
523
+ _logProcessor = (config, entry) => {
524
+ switch (entry.level) {
525
+ case LogLevel.ERROR:
526
+ case LogLevel.WARN:
527
+ case LogLevel.TRACE: {
528
+ const scope = entry.meta?.S;
529
+ const resource2 = this.resourceInstanceIndex.get(scope);
530
+ if (!resource2) {
531
+ return;
684
532
  }
685
- });
686
- const parentId = params.parentCtx.getAttribute(TRACE_SPAN_ATTRIBUTE);
687
- if (typeof parentId === "number") {
688
- this.parentId = parentId;
533
+ const context = {
534
+ ...entry.computedContext
535
+ };
536
+ if (entry.computedError !== void 0) {
537
+ context.error = entry.computedError;
538
+ }
539
+ const { filename, line } = entry.computedMeta;
540
+ const entryToPush = {
541
+ level: entry.level,
542
+ message: entry.message ?? entry.computedError ?? "",
543
+ context,
544
+ timestamp: new Date(entry.timestamp),
545
+ meta: {
546
+ file: filename ?? "",
547
+ line: line ?? 0,
548
+ resourceId: resource2.data.id
549
+ }
550
+ };
551
+ this._pushLog(entryToPush);
552
+ break;
689
553
  }
554
+ default:
690
555
  }
691
- }
692
- get name() {
693
- const resource2 = this._traceProcessor.resources.get(this.resourceId);
694
- return resource2 ? `${resource2.sanitizedClassName}#${resource2.data.instanceId}.${this.methodName}` : this.methodName;
695
- }
696
- get ctx() {
697
- return this._ctx;
698
- }
699
- markSuccess() {
700
- this.endTs = performance.now();
701
- this._traceProcessor._flushSpan(this);
702
- if (this._showInBrowserTimeline) {
703
- this._markInBrowserTimeline();
704
- }
705
- }
706
- markError(err) {
707
- this.endTs = performance.now();
708
- this.error = serializeError(err);
709
- this._traceProcessor._flushSpan(this);
710
- if (this._showInBrowserTimeline) {
711
- this._markInBrowserTimeline();
712
- }
713
- }
714
- serialize() {
715
- return {
716
- id: this.id,
717
- resourceId: this.resourceId ?? void 0,
718
- methodName: this.methodName,
719
- parentId: this.parentId ?? void 0,
720
- startTs: this.startTs.toFixed(3),
721
- endTs: this.endTs?.toFixed(3) ?? void 0,
722
- error: this.error ?? void 0
723
- };
724
- }
725
- _markInBrowserTimeline() {
726
- if (typeof globalThis?.performance?.measure === "function") {
727
- performance.measure(this.name, {
728
- start: this.startTs,
729
- end: this.endTs
730
- });
731
- }
732
- }
733
- };
734
- var serializeError = (err) => {
735
- if (err instanceof Error) {
736
- return {
737
- name: err.name,
738
- message: err.message
739
- };
740
- }
741
- return {
742
- message: String(err)
743
556
  };
744
557
  };
745
558
  var TRACE_PROCESSOR = globalThis.TRACE_PROCESSOR ??= new TraceProcessor();
@@ -788,33 +601,46 @@ var sanitizeValue = (value, depth, traceProcessor) => {
788
601
  return value.toString();
789
602
  }
790
603
  };
791
- var areEqualShallow = (a, b) => {
792
- for (const key in a) {
793
- if (!(key in b) || a[key] !== b[key]) {
794
- return false;
795
- }
796
- }
797
- for (const key in b) {
798
- if (!(key in a) || a[key] !== b[key]) {
799
- return false;
800
- }
801
- }
802
- return true;
803
- };
804
604
  var sanitizeClassName = (className) => {
605
+ let name = className.replace(/^_+/, "");
805
606
  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);
607
+ const m = name.match(SANITIZE_REGEX);
608
+ if (m) {
609
+ name = name.slice(0, -m[1].length);
811
610
  }
611
+ return name;
812
612
  };
813
613
  var isSetLike = (value) => value instanceof Set || typeof value === "object" && value !== null && Object.getPrototypeOf(value).constructor.name === "ComplexSet";
814
614
  var isMapLike = (value) => value instanceof Map || typeof value === "object" && value !== null && Object.getPrototypeOf(value).constructor.name === "ComplexMap";
815
615
 
816
- // packages/common/tracing/src/api.ts
616
+ // src/api.ts
617
+ var __dxlog_file4 = "/__w/dxos/dxos/packages/common/tracing/src/api.ts";
618
+ var LIFECYCLE_SPAN = /* @__PURE__ */ Symbol("dxos.tracing.lifecycle-span");
619
+ var TRACE_ALL_KEY = "dxos.debug.traceAll";
620
+ var collectSpanAttributes = (instance, spanAttributes) => {
621
+ const proto = Object.getPrototypeOf(instance);
622
+ if (!proto) {
623
+ return;
624
+ }
625
+ const tracingContext = getTracingContext(proto);
626
+ for (const [key, { options }] of Object.entries(tracingContext.infoProperties)) {
627
+ if (!options.spanAttribute) {
628
+ continue;
629
+ }
630
+ try {
631
+ const value = typeof instance[key] === "function" ? instance[key]() : instance[key];
632
+ if (value != null) {
633
+ const resolved = options.enum ? options.enum[value] : String(value);
634
+ spanAttributes[`ctx.${key}`] = resolved;
635
+ }
636
+ } catch {
637
+ }
638
+ }
639
+ };
817
640
  var resource = (options) => (constructor) => {
641
+ if (options?.lifecycle && !(constructor.prototype instanceof Resource)) {
642
+ throw new Error(`@trace.resource({ lifecycle: true }) requires ${constructor.name} to extend Resource`);
643
+ }
818
644
  const klass = /* @__PURE__ */ (() => class extends constructor {
819
645
  constructor(...rest) {
820
646
  super(...rest);
@@ -825,6 +651,65 @@ var resource = (options) => (constructor) => {
825
651
  });
826
652
  }
827
653
  })();
654
+ if (options?.lifecycle) {
655
+ const sanitizedName = sanitizeClassName(constructor.name);
656
+ const proto = klass.prototype;
657
+ const originalOpen = proto.open;
658
+ const originalClose = proto.close;
659
+ proto.open = async function(ctx) {
660
+ const self = this;
661
+ if (self._lifecycleState !== LifecycleState.CLOSED) {
662
+ return originalOpen.call(this, ctx);
663
+ }
664
+ const parentSpanContext = ctx?.getAttribute(TRACE_SPAN_ATTRIBUTE);
665
+ const resourceEntry = TRACE_PROCESSOR.resourceInstanceIndex.get(this);
666
+ const spanAttributes = {};
667
+ if (resourceEntry) {
668
+ spanAttributes.entryPoint = resourceEntry.sanitizedClassName;
669
+ }
670
+ const remoteSpan = TRACE_PROCESSOR.tracingBackend?.startSpan({
671
+ name: `${sanitizedName}.lifecycle`,
672
+ op: "lifecycle",
673
+ attributes: spanAttributes,
674
+ parentContext: parentSpanContext
675
+ });
676
+ self[LIFECYCLE_SPAN] = remoteSpan;
677
+ let openCtx = ctx;
678
+ if (remoteSpan?.spanContext != null) {
679
+ const traceAttrs = {
680
+ [TRACE_SPAN_ATTRIBUTE]: remoteSpan.spanContext
681
+ };
682
+ openCtx = ctx ? ctx.derive({
683
+ attributes: traceAttrs
684
+ }) : new Context2({
685
+ attributes: traceAttrs
686
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 79 });
687
+ }
688
+ try {
689
+ return await originalOpen.call(this, openCtx);
690
+ } catch (err) {
691
+ remoteSpan?.setError?.(err);
692
+ remoteSpan?.end();
693
+ self[LIFECYCLE_SPAN] = void 0;
694
+ throw err;
695
+ }
696
+ };
697
+ proto.close = async function(ctx) {
698
+ const self = this;
699
+ const remoteSpan = self[LIFECYCLE_SPAN];
700
+ try {
701
+ return await originalClose.call(this, ctx);
702
+ } catch (err) {
703
+ remoteSpan?.setError?.(err);
704
+ throw err;
705
+ } finally {
706
+ if (remoteSpan) {
707
+ remoteSpan.end();
708
+ self[LIFECYCLE_SPAN] = void 0;
709
+ }
710
+ }
711
+ };
712
+ }
828
713
  Object.defineProperty(klass, "name", {
829
714
  value: constructor.name
830
715
  });
@@ -838,45 +723,117 @@ var info = (opts = {}) => (target, propertyKey, descriptor) => {
838
723
  var mark = (name) => {
839
724
  performance.mark(name);
840
725
  };
841
- var span = ({ showInBrowserTimeline = false, op, attributes } = {}) => (target, propertyKey, descriptor) => {
726
+ var span = ({ showInBrowserTimeline = false, showInRemoteTracing = true, op, attributes } = {}) => (target, propertyKey, descriptor) => {
842
727
  const method = descriptor.value;
843
728
  descriptor.value = async function(...args) {
844
729
  const parentCtx = args[0] instanceof Context2 ? args[0] : null;
845
- const span2 = TRACE_PROCESSOR.traceSpan({
846
- parentCtx,
847
- methodName: propertyKey,
848
- instance: this,
849
- showInBrowserTimeline,
850
- op,
851
- attributes
852
- });
853
- const callArgs = span2.ctx ? [
854
- span2.ctx,
855
- ...args.slice(1)
856
- ] : args;
730
+ const startTs = performance.now();
731
+ const parentSpanContext = parentCtx?.getAttribute(TRACE_SPAN_ATTRIBUTE);
732
+ const resourceEntry = TRACE_PROCESSOR.resourceInstanceIndex.get(this);
733
+ const className = resourceEntry?.sanitizedClassName ?? sanitizeClassName(target.constructor?.name ?? "unknown");
734
+ const spanName = `${className}.${propertyKey}`;
735
+ const spanAttributes = {};
736
+ if (resourceEntry) {
737
+ spanAttributes.entryPoint = resourceEntry.sanitizedClassName;
738
+ }
739
+ collectSpanAttributes(this, spanAttributes);
740
+ if (attributes) {
741
+ for (const [key, value] of Object.entries(attributes)) {
742
+ spanAttributes[key.startsWith("ctx.") ? key : `ctx.${key}`] = value;
743
+ }
744
+ }
745
+ const remoteSpan = showInRemoteTracing ? TRACE_PROCESSOR.tracingBackend?.startSpan({
746
+ name: spanName,
747
+ op: op ?? "function",
748
+ attributes: spanAttributes,
749
+ parentContext: parentSpanContext
750
+ }) : void 0;
751
+ let callArgs = args;
752
+ if (parentCtx) {
753
+ const childCtx = remoteSpan?.spanContext != null ? parentCtx.derive({
754
+ attributes: {
755
+ [TRACE_SPAN_ATTRIBUTE]: remoteSpan.spanContext
756
+ }
757
+ }) : parentCtx.derive();
758
+ callArgs = [
759
+ childCtx,
760
+ ...args.slice(1)
761
+ ];
762
+ }
857
763
  try {
858
764
  return await method.apply(this, callArgs);
859
765
  } catch (err) {
860
- span2.markError(err);
766
+ remoteSpan?.setError?.(err);
861
767
  throw err;
862
768
  } finally {
863
- span2.markSuccess();
769
+ remoteSpan?.end();
770
+ if (showInBrowserTimeline && typeof globalThis?.performance?.measure === "function") {
771
+ performance.measure(spanName, {
772
+ start: startTs,
773
+ end: performance.now()
774
+ });
775
+ }
864
776
  }
865
777
  };
866
778
  };
867
- var spans = /* @__PURE__ */ new Map();
779
+ var manualSpans = /* @__PURE__ */ new Map();
780
+ var manualSpanTimestamps = /* @__PURE__ */ new Map();
868
781
  var spanStart = (params) => {
869
- if (spans.has(params.id)) {
870
- return;
782
+ if (manualSpans.has(params.id) || manualSpanTimestamps.has(params.id)) {
783
+ return params.parentCtx;
784
+ }
785
+ const resourceEntry = TRACE_PROCESSOR.resourceInstanceIndex.get(params.instance);
786
+ const className = resourceEntry?.sanitizedClassName ?? "unknown";
787
+ const spanName = `${className}.${params.methodName}`;
788
+ if (params.showInBrowserTimeline) {
789
+ manualSpanTimestamps.set(params.id, {
790
+ name: spanName,
791
+ startTs: performance.now()
792
+ });
793
+ }
794
+ if (params.showInRemoteTracing === false || !TRACE_PROCESSOR.tracingBackend) {
795
+ return params.parentCtx;
796
+ }
797
+ const parentSpanContext = params.parentCtx?.getAttribute(TRACE_SPAN_ATTRIBUTE);
798
+ const spanAttributes = {};
799
+ if (resourceEntry) {
800
+ spanAttributes.entryPoint = resourceEntry.sanitizedClassName;
871
801
  }
872
- const span2 = TRACE_PROCESSOR.traceSpan(params);
873
- spans.set(params.id, span2);
802
+ collectSpanAttributes(params.instance, spanAttributes);
803
+ if (params.attributes) {
804
+ for (const [key, value] of Object.entries(params.attributes)) {
805
+ spanAttributes[key.startsWith("ctx.") ? key : `ctx.${key}`] = value;
806
+ }
807
+ }
808
+ const remoteSpan = TRACE_PROCESSOR.tracingBackend.startSpan({
809
+ name: spanName,
810
+ op: params.op ?? "function",
811
+ attributes: spanAttributes,
812
+ parentContext: parentSpanContext
813
+ });
814
+ manualSpans.set(params.id, remoteSpan);
815
+ if (params.parentCtx && remoteSpan.spanContext != null) {
816
+ return params.parentCtx.derive({
817
+ attributes: {
818
+ [TRACE_SPAN_ATTRIBUTE]: remoteSpan.spanContext
819
+ }
820
+ });
821
+ }
822
+ return params.parentCtx;
874
823
  };
875
824
  var spanEnd = (id) => {
876
- const span2 = spans.get(id);
877
- if (span2) {
878
- span2.markSuccess();
879
- spans.delete(id);
825
+ const remoteSpan = manualSpans.get(id);
826
+ if (remoteSpan) {
827
+ remoteSpan.end();
828
+ manualSpans.delete(id);
829
+ }
830
+ const timestamps = manualSpanTimestamps.get(id);
831
+ if (timestamps && typeof globalThis?.performance?.measure === "function") {
832
+ performance.measure(timestamps.name, {
833
+ start: timestamps.startTs,
834
+ end: performance.now()
835
+ });
836
+ manualSpanTimestamps.delete(id);
880
837
  }
881
838
  };
882
839
  var metricsCounter = () => (target, propertyKey, descriptor) => {
@@ -901,8 +858,13 @@ var trace = {
901
858
  metrics: TRACE_PROCESSOR.remoteMetrics
902
859
  };
903
860
 
904
- // packages/common/tracing/src/metrics/base.ts
861
+ // src/metrics/base.ts
905
862
  var BaseCounter = class {
863
+ /**
864
+ * @internal
865
+ */
866
+ _instance;
867
+ name;
906
868
  /**
907
869
  * @internal
908
870
  */
@@ -914,11 +876,12 @@ var BaseCounter = class {
914
876
  }
915
877
  };
916
878
 
917
- // packages/common/tracing/src/metrics/unary-counter.ts
879
+ // src/metrics/unary-counter.ts
918
880
  var UnaryCounter = class extends BaseCounter {
881
+ value = 0;
882
+ units;
919
883
  constructor({ units } = {}) {
920
884
  super();
921
- this.value = 0;
922
885
  this.units = units;
923
886
  }
924
887
  inc(by = 1) {
@@ -935,14 +898,15 @@ var UnaryCounter = class extends BaseCounter {
935
898
  }
936
899
  };
937
900
 
938
- // packages/common/tracing/src/metrics/time-series-counter.ts
901
+ // src/metrics/time-series-counter.ts
939
902
  var MAX_BUCKETS = 60;
940
903
  var TimeSeriesCounter = class extends BaseCounter {
904
+ _currentValue = 0;
905
+ _totalValue = 0;
906
+ _buckets = [];
907
+ units;
941
908
  constructor({ units } = {}) {
942
909
  super();
943
- this._currentValue = 0;
944
- this._totalValue = 0;
945
- this._buckets = [];
946
910
  this.units = units;
947
911
  }
948
912
  inc(by = 1) {
@@ -975,16 +939,13 @@ var TimeSeriesCounter = class extends BaseCounter {
975
939
  }
976
940
  };
977
941
 
978
- // packages/common/tracing/src/metrics/time-usage-counter.ts
942
+ // src/metrics/time-usage-counter.ts
979
943
  var MAX_BUCKETS2 = 60;
980
944
  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
- }
945
+ _currentValue = 0;
946
+ _totalValue = 0;
947
+ _buckets = [];
948
+ _lastTickTime = performance.now();
988
949
  record(time) {
989
950
  this._currentValue += time;
990
951
  this._totalValue += time;
@@ -1027,11 +988,12 @@ var TimeUsageCounter = class extends BaseCounter {
1027
988
  }
1028
989
  };
1029
990
 
1030
- // packages/common/tracing/src/metrics/map-counter.ts
991
+ // src/metrics/map-counter.ts
1031
992
  var MapCounter = class extends BaseCounter {
993
+ values = /* @__PURE__ */ new Map();
994
+ units;
1032
995
  constructor({ units } = {}) {
1033
996
  super();
1034
- this.values = /* @__PURE__ */ new Map();
1035
997
  this.units = units;
1036
998
  }
1037
999
  inc(key, by = 1) {
@@ -1052,8 +1014,9 @@ var MapCounter = class extends BaseCounter {
1052
1014
  }
1053
1015
  };
1054
1016
 
1055
- // packages/common/tracing/src/metrics/custom-counter.ts
1017
+ // src/metrics/custom-counter.ts
1056
1018
  var CustomCounter = class extends BaseCounter {
1019
+ _getData;
1057
1020
  constructor(_getData) {
1058
1021
  super(), this._getData = _getData;
1059
1022
  }
@@ -1067,7 +1030,7 @@ var CustomCounter = class extends BaseCounter {
1067
1030
  }
1068
1031
  };
1069
1032
 
1070
- // packages/common/tracing/src/index.ts
1033
+ // src/index.ts
1071
1034
  trace.diagnostic({
1072
1035
  id: "process-info",
1073
1036
  name: "Process Info",
@@ -1088,16 +1051,13 @@ export {
1088
1051
  DiagnosticsManager,
1089
1052
  MapCounter,
1090
1053
  RemoteMetrics,
1091
- RemoteTracing,
1092
1054
  ResourceEntry,
1055
+ TRACE_ALL_KEY,
1093
1056
  TRACE_PROCESSOR,
1094
- TRACE_SPAN_ATTRIBUTE,
1095
1057
  TimeSeriesCounter,
1096
1058
  TimeUsageCounter,
1097
1059
  TraceDiagnosticImpl,
1098
1060
  TraceProcessor,
1099
- TraceSender,
1100
- TracingSpan,
1101
1061
  UnaryCounter,
1102
1062
  getTracingContext,
1103
1063
  sanitizeClassName,