@dxos/tracing 0.10.0 → 0.11.1

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 (47) hide show
  1. package/dist/lib/index.mjs +509 -0
  2. package/dist/lib/index.mjs.map +1 -0
  3. package/dist/types/src/api.d.ts +0 -44
  4. package/dist/types/src/api.d.ts.map +1 -1
  5. package/dist/types/src/index.d.ts +0 -2
  6. package/dist/types/src/index.d.ts.map +1 -1
  7. package/dist/types/src/trace-processor.d.ts +0 -40
  8. package/dist/types/src/trace-processor.d.ts.map +1 -1
  9. package/dist/types/tsconfig.tsbuildinfo +1 -1
  10. package/package.json +10 -13
  11. package/src/api.ts +3 -186
  12. package/src/index.ts +0 -2
  13. package/src/trace-processor.ts +1 -274
  14. package/src/tracing.test.ts +41 -326
  15. package/dist/lib/browser/index.mjs +0 -1065
  16. package/dist/lib/browser/index.mjs.map +0 -7
  17. package/dist/lib/browser/meta.json +0 -1
  18. package/dist/lib/node-esm/index.mjs +0 -1067
  19. package/dist/lib/node-esm/index.mjs.map +0 -7
  20. package/dist/lib/node-esm/meta.json +0 -1
  21. package/dist/types/src/metrics/base.d.ts +0 -7
  22. package/dist/types/src/metrics/base.d.ts.map +0 -1
  23. package/dist/types/src/metrics/custom-counter.d.ts +0 -8
  24. package/dist/types/src/metrics/custom-counter.d.ts.map +0 -1
  25. package/dist/types/src/metrics/index.d.ts +0 -7
  26. package/dist/types/src/metrics/index.d.ts.map +0 -1
  27. package/dist/types/src/metrics/map-counter.d.ts +0 -12
  28. package/dist/types/src/metrics/map-counter.d.ts.map +0 -1
  29. package/dist/types/src/metrics/time-series-counter.d.ts +0 -15
  30. package/dist/types/src/metrics/time-series-counter.d.ts.map +0 -1
  31. package/dist/types/src/metrics/time-usage-counter.d.ts +0 -15
  32. package/dist/types/src/metrics/time-usage-counter.d.ts.map +0 -1
  33. package/dist/types/src/metrics/unary-counter.d.ts +0 -12
  34. package/dist/types/src/metrics/unary-counter.d.ts.map +0 -1
  35. package/dist/types/src/symbols.d.ts +0 -10
  36. package/dist/types/src/symbols.d.ts.map +0 -1
  37. package/dist/types/src/weak-ref.d.ts +0 -2
  38. package/dist/types/src/weak-ref.d.ts.map +0 -1
  39. package/src/metrics/base.ts +0 -26
  40. package/src/metrics/custom-counter.ts +0 -22
  41. package/src/metrics/index.ts +0 -10
  42. package/src/metrics/map-counter.ts +0 -35
  43. package/src/metrics/time-series-counter.ts +0 -52
  44. package/src/metrics/time-usage-counter.ts +0 -62
  45. package/src/metrics/unary-counter.ts +0 -31
  46. package/src/symbols.ts +0 -24
  47. package/src/weak-ref.ts +0 -18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/tracing",
3
- "version": "0.10.0",
3
+ "version": "0.11.1",
4
4
  "description": "Async utilities.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -14,12 +14,9 @@
14
14
  "type": "module",
15
15
  "exports": {
16
16
  ".": {
17
+ "source": "./src/index.ts",
17
18
  "types": "./dist/types/src/index.d.ts",
18
- "browser": "./dist/lib/browser/index.mjs",
19
- "node": {
20
- "require": "./dist/lib/node/index.cjs",
21
- "default": "./dist/lib/node-esm/index.mjs"
22
- }
19
+ "import": "./dist/lib/index.mjs"
23
20
  }
24
21
  },
25
22
  "types": "dist/types/src/index.d.ts",
@@ -28,13 +25,13 @@
28
25
  "src"
29
26
  ],
30
27
  "dependencies": {
31
- "@dxos/async": "0.10.0",
32
- "@dxos/invariant": "0.10.0",
33
- "@dxos/log": "0.10.0",
34
- "@dxos/context": "0.10.0",
35
- "@dxos/node-std": "0.10.0",
36
- "@dxos/protocols": "0.10.0",
37
- "@dxos/util": "0.10.0"
28
+ "@dxos/async": "0.11.1",
29
+ "@dxos/context": "0.11.1",
30
+ "@dxos/invariant": "0.11.1",
31
+ "@dxos/log": "0.11.1",
32
+ "@dxos/node-std": "0.11.1",
33
+ "@dxos/protocols": "0.11.1",
34
+ "@dxos/util": "0.11.1"
38
35
  },
39
36
  "publishConfig": {
40
37
  "access": "public"
package/src/api.ts CHANGED
@@ -2,178 +2,15 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { Context, LifecycleState, Resource, TRACE_SPAN_ATTRIBUTE } from '@dxos/context';
5
+ import { Context, TRACE_SPAN_ATTRIBUTE } from '@dxos/context';
6
6
  import { type MaybePromise } from '@dxos/util';
7
7
 
8
- import { getTracingContext } from './symbols';
9
8
  import { TRACE_PROCESSOR, sanitizeClassName } from './trace-processor';
10
9
  import type { RemoteSpan } from './tracing-types';
11
10
 
12
- const LIFECYCLE_SPAN = Symbol('dxos.tracing.lifecycle-span');
13
-
14
11
  /** localStorage key that switches the browser OTEL sampler from 30% to 100%. */
15
12
  export const TRACE_ALL_KEY = 'dxos.debug.traceAll';
16
13
 
17
- /**
18
- * Reads `@trace.info({ spanAttribute: true })` properties from the instance
19
- * and writes them into the span attributes map.
20
- */
21
- const collectSpanAttributes = (instance: any, spanAttributes: Record<string, any>) => {
22
- const proto = Object.getPrototypeOf(instance);
23
- if (!proto) {
24
- return;
25
- }
26
- const tracingContext = getTracingContext(proto);
27
- for (const [key, { options }] of Object.entries(tracingContext.infoProperties)) {
28
- if (!options.spanAttribute) {
29
- continue;
30
- }
31
- try {
32
- const value = typeof instance[key] === 'function' ? instance[key]() : instance[key];
33
- if (value != null) {
34
- const resolved = options.enum ? options.enum[value] : String(value);
35
- spanAttributes[`ctx.${key}`] = resolved;
36
- }
37
- } catch {
38
- // Skip properties that throw (e.g. uninitialized).
39
- }
40
- }
41
- };
42
-
43
- export type ResourceOptions = {
44
- annotation?: symbol;
45
- /**
46
- * Start a lifecycle span on `open()` and end it on `close()`.
47
- * `this._ctx` carries the lifecycle span's trace context, so background work
48
- * (subscriptions, timers) becomes children of the lifecycle span.
49
- * Direct calls within `_open` use the `_open` span's context as usual.
50
- * Requires the class to extend {@link Resource}.
51
- */
52
- lifecycle?: boolean;
53
- };
54
-
55
- /**
56
- * Annotates a class as a tracked resource.
57
- */
58
- const resource =
59
- (options?: ResourceOptions) =>
60
- <T extends { new (...args: any[]): {} }>(constructor: T) => {
61
- if (options?.lifecycle && !(constructor.prototype instanceof Resource)) {
62
- throw new Error(`@trace.resource({ lifecycle: true }) requires ${constructor.name} to extend Resource`);
63
- }
64
-
65
- const klass = (() =>
66
- class extends constructor {
67
- constructor(...rest: any[]) {
68
- super(...rest);
69
- TRACE_PROCESSOR.createTraceResource({ constructor, annotation: options?.annotation, instance: this });
70
- }
71
- })();
72
-
73
- if (options?.lifecycle) {
74
- const sanitizedName = sanitizeClassName(constructor.name);
75
- const proto = klass.prototype as any;
76
- const originalOpen = proto.open;
77
- const originalClose = proto.close;
78
-
79
- proto.open = async function (ctx?: Context): Promise<any> {
80
- const self = this as any;
81
-
82
- if (self._lifecycleState !== LifecycleState.CLOSED) {
83
- return originalOpen.call(this, ctx);
84
- }
85
-
86
- const parentSpanContext = ctx?.getAttribute(TRACE_SPAN_ATTRIBUTE);
87
- const resourceEntry = TRACE_PROCESSOR.resourceInstanceIndex.get(this);
88
- const spanAttributes: Record<string, any> = {};
89
- if (resourceEntry) {
90
- spanAttributes.entryPoint = resourceEntry.sanitizedClassName;
91
- }
92
-
93
- const remoteSpan = TRACE_PROCESSOR.tracingBackend?.startSpan({
94
- name: `${sanitizedName}.lifecycle`,
95
- op: 'lifecycle',
96
- attributes: spanAttributes,
97
- parentContext: parentSpanContext,
98
- });
99
- self[LIFECYCLE_SPAN] = remoteSpan;
100
-
101
- let openCtx = ctx;
102
- if (remoteSpan?.spanContext != null) {
103
- const traceAttrs = { [TRACE_SPAN_ATTRIBUTE]: remoteSpan.spanContext };
104
- openCtx = ctx ? ctx.derive({ attributes: traceAttrs }) : new Context({ attributes: traceAttrs });
105
- }
106
-
107
- try {
108
- return await originalOpen.call(this, openCtx);
109
- } catch (err) {
110
- remoteSpan?.setError?.(err);
111
- remoteSpan?.end();
112
- self[LIFECYCLE_SPAN] = undefined;
113
- throw err;
114
- }
115
- };
116
-
117
- proto.close = async function (ctx?: Context): Promise<any> {
118
- const self = this as any;
119
- const remoteSpan: RemoteSpan | undefined = self[LIFECYCLE_SPAN];
120
- try {
121
- return await originalClose.call(this, ctx);
122
- } catch (err) {
123
- remoteSpan?.setError?.(err);
124
- throw err;
125
- } finally {
126
- if (remoteSpan) {
127
- remoteSpan.end();
128
- self[LIFECYCLE_SPAN] = undefined;
129
- }
130
- }
131
- };
132
- }
133
-
134
- Object.defineProperty(klass, 'name', { value: constructor.name });
135
- return klass;
136
- };
137
-
138
- export interface TimeAware {
139
- tick(timeMs: number): void;
140
- }
141
-
142
- export type InfoOptions = {
143
- /**
144
- * Value is of enum type and should be converted to string.
145
- *
146
- * Example:
147
- *
148
- * ```ts
149
- * @trace.info({ enum: SpaceState })
150
- * get state(): SpaceState { ... }
151
- * ```
152
- */
153
- enum?: Record<string, any>;
154
-
155
- /**
156
- * Max depth of the object to be included in the resource info section.
157
- *
158
- * null means no limit (a limit of 8 nested objects is still imposed).
159
- *
160
- * Default: 0 - objects will be stringified with toString.
161
- */
162
- depth?: number | null;
163
-
164
- /** When true, the property value is also set as an OTEL span attribute on every span created by this resource. */
165
- spanAttribute?: boolean;
166
- };
167
-
168
- /**
169
- * Marks a property or a method to be included in the resource info section.
170
- */
171
- const info =
172
- (opts: InfoOptions = {}) =>
173
- (target: any, propertyKey: string, descriptor?: PropertyDescriptor) => {
174
- getTracingContext(target).infoProperties[propertyKey] = { options: opts };
175
- };
176
-
177
14
  const mark = (name: string) => {
178
15
  performance.mark(name);
179
16
  };
@@ -201,15 +38,10 @@ const span =
201
38
 
202
39
  const parentSpanContext = parentCtx?.getAttribute(TRACE_SPAN_ATTRIBUTE);
203
40
 
204
- const resourceEntry = TRACE_PROCESSOR.resourceInstanceIndex.get(this);
205
- const className = resourceEntry?.sanitizedClassName ?? sanitizeClassName(target.constructor?.name ?? 'unknown');
41
+ const className = sanitizeClassName(target.constructor?.name ?? 'unknown');
206
42
  const spanName = `${className}.${propertyKey}`;
207
43
 
208
44
  const spanAttributes: Record<string, any> = {};
209
- if (resourceEntry) {
210
- spanAttributes.entryPoint = resourceEntry.sanitizedClassName;
211
- }
212
- collectSpanAttributes(this, spanAttributes);
213
45
  if (attributes) {
214
46
  for (const [key, value] of Object.entries(attributes)) {
215
47
  spanAttributes[key.startsWith('ctx.') ? key : `ctx.${key}`] = value;
@@ -278,8 +110,7 @@ const spanStart = (params: ManualSpanParams): Context | null => {
278
110
  return params.parentCtx;
279
111
  }
280
112
 
281
- const resourceEntry = TRACE_PROCESSOR.resourceInstanceIndex.get(params.instance);
282
- const className = resourceEntry?.sanitizedClassName ?? 'unknown';
113
+ const className = sanitizeClassName(params.instance?.constructor?.name ?? 'unknown');
283
114
  const spanName = `${className}.${params.methodName}`;
284
115
 
285
116
  if (params.showInBrowserTimeline) {
@@ -293,10 +124,6 @@ const spanStart = (params: ManualSpanParams): Context | null => {
293
124
  const parentSpanContext = params.parentCtx?.getAttribute(TRACE_SPAN_ATTRIBUTE);
294
125
 
295
126
  const spanAttributes: Record<string, any> = {};
296
- if (resourceEntry) {
297
- spanAttributes.entryPoint = resourceEntry.sanitizedClassName;
298
- }
299
- collectSpanAttributes(params.instance, spanAttributes);
300
127
  if (params.attributes) {
301
128
  for (const [key, value] of Object.entries(params.attributes)) {
302
129
  spanAttributes[key.startsWith('ctx.') ? key : `ctx.${key}`] = value;
@@ -334,13 +161,6 @@ const spanEnd = (id: string) => {
334
161
  }
335
162
  };
336
163
 
337
- /**
338
- * Attaches metrics counter to the resource.
339
- */
340
- const metricsCounter = () => (target: any, propertyKey: string, descriptor?: PropertyDescriptor) => {
341
- getTracingContext(target).metricsProperties[propertyKey] = {};
342
- };
343
-
344
164
  export type AddLinkOptions = {};
345
165
 
346
166
  const addLink = (parent: any, child: any, opts: AddLinkOptions = {}) => {
@@ -376,10 +196,7 @@ const diagnostic = <T>(params: TraceDiagnosticProps<T>): TraceDiagnostic => {
376
196
  export const trace = {
377
197
  addLink,
378
198
  diagnostic,
379
- info,
380
199
  mark,
381
- metricsCounter,
382
- resource,
383
200
  span,
384
201
  spanStart,
385
202
  spanEnd,
package/src/index.ts CHANGED
@@ -5,10 +5,8 @@
5
5
  import { trace } from './api';
6
6
 
7
7
  export * from './api';
8
- export * from './symbols';
9
8
  export * from './trace-processor';
10
9
  export * from './tracing-types';
11
- export * from './metrics';
12
10
  export * from './diagnostic';
13
11
  export * from './diagnostics-channel';
14
12
  export * from './remote/metrics';
@@ -2,57 +2,12 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { LogLevel, type LogProcessor, log } from '@dxos/log';
6
- import { type LogEntry } from '@dxos/protocols/proto/dxos/client/services';
7
- import { type Metric, type Resource } from '@dxos/protocols/proto/dxos/tracing';
8
- import { getPrototypeSpecificInstanceId } from '@dxos/util';
9
-
10
- import type { AddLinkOptions, TimeAware } from './api';
5
+ import type { AddLinkOptions } from './api';
11
6
  import { BUFFERED_PREFIX, BufferingTracingBackend } from './buffering-backend';
12
7
  import { DiagnosticsManager } from './diagnostic';
13
8
  import { DiagnosticsChannel } from './diagnostics-channel';
14
- import { type BaseCounter } from './metrics';
15
9
  import { RemoteMetrics } from './remote/metrics';
16
- import { getTracingContext } from './symbols';
17
10
  import type { RemoteSpan, StartSpanOptions, TracingBackend } from './tracing-types';
18
- import { WeakRef } from './weak-ref';
19
-
20
- export type Diagnostics = {
21
- resources: Record<string, Resource>;
22
- logs: LogEntry[];
23
- };
24
-
25
- export type TraceResourceConstructorProps = {
26
- constructor: { new (...args: any[]): {} };
27
- instance: any;
28
- annotation?: symbol;
29
- };
30
-
31
- export class ResourceEntry {
32
- /**
33
- * Sometimes bundlers mangle class names: WebFile -> WebFile2.
34
- *
35
- * We use a heuristic to remove the suffix.
36
- */
37
- public readonly sanitizedClassName: string;
38
-
39
- constructor(
40
- public readonly data: Resource,
41
- public readonly instance: WeakRef<any>,
42
- public readonly annotation?: symbol,
43
- ) {
44
- this.sanitizedClassName = sanitizeClassName(data.className);
45
- }
46
-
47
- getMetric(name: string): Metric | undefined {
48
- return this.data.metrics?.find((metric) => metric.name === name);
49
- }
50
- }
51
-
52
- const MAX_RESOURCE_RECORDS = 2_000;
53
- const MAX_LOG_RECORDS = 1_000;
54
-
55
- const MAX_INFO_OBJECT_DEPTH = 8;
56
11
 
57
12
  export class TraceProcessor {
58
13
  public readonly diagnostics = new DiagnosticsManager();
@@ -96,17 +51,9 @@ export class TraceProcessor {
96
51
  };
97
52
  }
98
53
 
99
- readonly resources = new Map<number, ResourceEntry>();
100
- readonly resourceInstanceIndex = new WeakMap<any, ResourceEntry>();
101
- readonly resourceIdList: number[] = [];
102
-
103
- readonly logs: LogEntry[] = [];
104
-
105
54
  private _instanceTag: string | null = null;
106
55
 
107
56
  constructor() {
108
- log.addProcessor(this._logProcessor.bind(this));
109
-
110
57
  if (DiagnosticsChannel.supported) {
111
58
  this.diagnosticsChannel.serve(this.diagnostics);
112
59
  }
@@ -118,224 +65,12 @@ export class TraceProcessor {
118
65
  this.diagnostics.setInstanceTag(tag);
119
66
  }
120
67
 
121
- /** @internal */
122
- createTraceResource(params: TraceResourceConstructorProps): void {
123
- const id = this.resources.size;
124
-
125
- const tracingContext = getTracingContext(Object.getPrototypeOf(params.instance));
126
- for (const key of Object.keys(tracingContext.metricsProperties)) {
127
- (params.instance[key] as BaseCounter)._assign(params.instance, key);
128
- }
129
-
130
- const entry = new ResourceEntry(
131
- {
132
- id,
133
- className: params.constructor.name,
134
- instanceId: getPrototypeSpecificInstanceId(params.instance),
135
- info: this.getResourceInfo(params.instance),
136
- links: [],
137
- metrics: this.getResourceMetrics(params.instance),
138
- },
139
- new WeakRef(params.instance),
140
- params.annotation,
141
- );
142
-
143
- this.resources.set(id, entry);
144
- this.resourceInstanceIndex.set(params.instance, entry);
145
- this.resourceIdList.push(id);
146
- if (this.resourceIdList.length > MAX_RESOURCE_RECORDS) {
147
- this._clearResources();
148
- }
149
- }
150
-
151
68
  // TODO(burdon): Not implemented.
152
69
  addLink(parent: any, child: any, opts: AddLinkOptions): void {}
153
-
154
- getDiagnostics(): Diagnostics {
155
- this.refresh();
156
-
157
- return {
158
- resources: Object.fromEntries(
159
- Array.from(this.resources.entries()).map(([id, entry]) => [
160
- `${entry.sanitizedClassName}#${entry.data.instanceId}`,
161
- entry.data,
162
- ]),
163
- ),
164
- logs: this.logs.filter((log) => log.level >= LogLevel.INFO),
165
- };
166
- }
167
-
168
- getResourceInfo(instance: any): Record<string, any> {
169
- const res: Record<string, any> = {};
170
- const tracingContext = getTracingContext(Object.getPrototypeOf(instance));
171
- for (const [key, { options }] of Object.entries(tracingContext.infoProperties)) {
172
- try {
173
- const value = typeof instance[key] === 'function' ? instance[key]() : instance[key];
174
- if (options.enum) {
175
- res[key] = options.enum[value];
176
- } else {
177
- res[key] = sanitizeValue(
178
- value,
179
- options.depth === undefined ? 1 : (options.depth ?? MAX_INFO_OBJECT_DEPTH),
180
- this,
181
- );
182
- }
183
- } catch (err: any) {
184
- res[key] = err.message;
185
- }
186
- }
187
-
188
- return res;
189
- }
190
-
191
- getResourceMetrics(instance: any): Metric[] {
192
- const res: Metric[] = [];
193
- const tracingContext = getTracingContext(Object.getPrototypeOf(instance));
194
- for (const [key, _opts] of Object.entries(tracingContext.metricsProperties)) {
195
- res.push(instance[key].getData());
196
- }
197
-
198
- return res;
199
- }
200
-
201
- getResourceId(instance: any): number | null {
202
- const entry = this.resourceInstanceIndex.get(instance);
203
- return entry ? entry.data.id : null;
204
- }
205
-
206
- findResourcesByClassName(className: string): ResourceEntry[] {
207
- return [...this.resources.values()].filter(
208
- (res) => res.data.className === className || res.sanitizedClassName === className,
209
- );
210
- }
211
-
212
- findResourcesByAnnotation(annotation: symbol): ResourceEntry[] {
213
- return [...this.resources.values()].filter((res) => res.annotation === annotation);
214
- }
215
-
216
- refresh(): void {
217
- for (const resource of this.resources.values()) {
218
- const instance = resource.instance.deref();
219
- if (!instance) {
220
- continue;
221
- }
222
-
223
- const tracingContext = getTracingContext(Object.getPrototypeOf(instance));
224
- const time = performance.now();
225
- (instance as TimeAware).tick?.(time);
226
- for (const key of Object.keys(tracingContext.metricsProperties)) {
227
- (instance[key] as BaseCounter)._tick?.(time);
228
- }
229
-
230
- resource.data.info = this.getResourceInfo(instance);
231
- resource.data.metrics = this.getResourceMetrics(instance);
232
- }
233
- }
234
-
235
- private _clearResources(): void {
236
- while (this.resourceIdList.length > MAX_RESOURCE_RECORDS) {
237
- const id = this.resourceIdList.shift()!;
238
- this.resources.delete(id);
239
- }
240
- }
241
-
242
- private _pushLog(log: LogEntry): void {
243
- this.logs.push(log);
244
- if (this.logs.length > MAX_LOG_RECORDS) {
245
- this.logs.shift();
246
- }
247
- }
248
-
249
- private _logProcessor: LogProcessor = (config, entry) => {
250
- switch (entry.level) {
251
- case LogLevel.ERROR:
252
- case LogLevel.WARN:
253
- case LogLevel.TRACE: {
254
- const scope = entry.meta?.S;
255
- const resource = this.resourceInstanceIndex.get(scope);
256
- if (!resource) {
257
- return;
258
- }
259
-
260
- const context: Record<string, any> = { ...entry.computedContext };
261
- if (entry.computedError !== undefined) {
262
- context.error = entry.computedError;
263
- }
264
-
265
- const { filename, line } = entry.computedMeta;
266
- const entryToPush: LogEntry = {
267
- level: entry.level,
268
- message: entry.message ?? entry.computedError ?? '',
269
- context,
270
- timestamp: new Date(entry.timestamp),
271
- meta: {
272
- file: filename ?? '',
273
- line: line ?? 0,
274
- resourceId: resource.data.id,
275
- },
276
- };
277
- this._pushLog(entryToPush);
278
- break;
279
- }
280
- default:
281
- }
282
- };
283
70
  }
284
71
 
285
72
  export const TRACE_PROCESSOR: TraceProcessor = ((globalThis as any).TRACE_PROCESSOR ??= new TraceProcessor());
286
73
 
287
- const sanitizeValue = (value: any, depth: number, traceProcessor: TraceProcessor): any => {
288
- switch (typeof value) {
289
- case 'string':
290
- case 'number':
291
- case 'boolean':
292
- case 'undefined':
293
- return value;
294
- case 'object':
295
- case 'function':
296
- if (value === null) {
297
- return value;
298
- }
299
-
300
- {
301
- const resourceEntry = traceProcessor.resourceInstanceIndex.get(value);
302
- if (resourceEntry) {
303
- return `${resourceEntry.sanitizedClassName}#${resourceEntry.data.instanceId}`;
304
- }
305
- }
306
-
307
- if (typeof value.toJSON === 'function') {
308
- return sanitizeValue(value.toJSON(), depth, traceProcessor);
309
- }
310
-
311
- if (depth > 0) {
312
- if (isSetLike(value)) {
313
- return Object.fromEntries(
314
- Array.from(value.entries()).map((value) => sanitizeValue(value, depth - 1, traceProcessor)),
315
- );
316
- } else if (isMapLike(value)) {
317
- return Object.fromEntries(
318
- Array.from(value.entries()).map(([key, value]) => [key, sanitizeValue(value, depth - 1, traceProcessor)]),
319
- );
320
- } else if (Array.isArray(value)) {
321
- return value.map((item: any) => sanitizeValue(item, depth - 1, traceProcessor));
322
- } else if (typeof value === 'object') {
323
- const res: any = {};
324
- for (const key of Object.keys(value)) {
325
- res[key] = sanitizeValue(value[key], depth - 1, traceProcessor);
326
- }
327
- return res;
328
- }
329
- }
330
-
331
- if (typeof value.truncate === 'function') {
332
- return value.truncate();
333
- }
334
-
335
- return value.toString();
336
- }
337
- };
338
-
339
74
  export const sanitizeClassName = (className: string) => {
340
75
  let name = className.replace(/^_+/, '');
341
76
  const SANITIZE_REGEX = /[^_](\d+)$/;
@@ -345,11 +80,3 @@ export const sanitizeClassName = (className: string) => {
345
80
  }
346
81
  return name;
347
82
  };
348
-
349
- const isSetLike = (value: any): value is Set<any> =>
350
- value instanceof Set ||
351
- (typeof value === 'object' && value !== null && Object.getPrototypeOf(value).constructor.name === 'ComplexSet');
352
-
353
- const isMapLike = (value: any): value is Map<any, any> =>
354
- value instanceof Map ||
355
- (typeof value === 'object' && value !== null && Object.getPrototypeOf(value).constructor.name === 'ComplexMap');