@dxos/tracing 0.8.4-main.72ec0f3 → 0.8.4-main.74a063c4e0
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 +7 -5
- package/dist/types/src/api.d.ts.map +1 -1
- package/dist/types/src/diagnostic.d.ts +2 -2
- package/dist/types/src/diagnostic.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 +11 -6
- package/dist/types/src/trace-processor.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -9
- package/src/api.ts +23 -16
- package/src/diagnostic.ts +2 -2
- package/src/remote/tracing.ts +133 -11
- package/src/trace-processor.ts +30 -18
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/tracing",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.74a063c4e0",
|
|
4
4
|
"description": "Async utilities.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/dxos/dxos"
|
|
10
|
+
},
|
|
7
11
|
"license": "MIT",
|
|
8
12
|
"author": "DXOS.org",
|
|
9
13
|
"sideEffects": true,
|
|
@@ -27,14 +31,14 @@
|
|
|
27
31
|
"src"
|
|
28
32
|
],
|
|
29
33
|
"dependencies": {
|
|
30
|
-
"@dxos/async": "0.8.4-main.
|
|
31
|
-
"@dxos/codec-protobuf": "0.8.4-main.
|
|
32
|
-
"@dxos/context": "0.8.4-main.
|
|
33
|
-
"@dxos/invariant": "0.8.4-main.
|
|
34
|
-
"@dxos/log": "0.8.4-main.
|
|
35
|
-
"@dxos/
|
|
36
|
-
"@dxos/protocols": "0.8.4-main.
|
|
37
|
-
"@dxos/
|
|
34
|
+
"@dxos/async": "0.8.4-main.74a063c4e0",
|
|
35
|
+
"@dxos/codec-protobuf": "0.8.4-main.74a063c4e0",
|
|
36
|
+
"@dxos/context": "0.8.4-main.74a063c4e0",
|
|
37
|
+
"@dxos/invariant": "0.8.4-main.74a063c4e0",
|
|
38
|
+
"@dxos/log": "0.8.4-main.74a063c4e0",
|
|
39
|
+
"@dxos/util": "0.8.4-main.74a063c4e0",
|
|
40
|
+
"@dxos/protocols": "0.8.4-main.74a063c4e0",
|
|
41
|
+
"@dxos/node-std": "0.8.4-main.74a063c4e0"
|
|
38
42
|
},
|
|
39
43
|
"publishConfig": {
|
|
40
44
|
"access": "public"
|
package/src/api.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { Context } from '@dxos/context';
|
|
|
6
6
|
import { type MaybePromise } from '@dxos/util';
|
|
7
7
|
|
|
8
8
|
import { getTracingContext } from './symbols';
|
|
9
|
-
import { TRACE_PROCESSOR, type
|
|
9
|
+
import { TRACE_PROCESSOR, type TraceSpanProps, type TracingSpan } from './trace-processor';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Annotates a class as a tracked resource.
|
|
@@ -68,6 +68,8 @@ const mark = (name: string) => {
|
|
|
68
68
|
|
|
69
69
|
export type SpanOptions = {
|
|
70
70
|
showInBrowserTimeline?: boolean;
|
|
71
|
+
/** When false the span is not exported to remote OTLP collectors. Defaults to true. */
|
|
72
|
+
showInRemoteTracing?: boolean;
|
|
71
73
|
op?: string;
|
|
72
74
|
attributes?: Record<string, any>;
|
|
73
75
|
};
|
|
@@ -76,30 +78,35 @@ export type SpanOptions = {
|
|
|
76
78
|
* Decorator that creates a span for the execution duration of the decorated method.
|
|
77
79
|
*/
|
|
78
80
|
const span =
|
|
79
|
-
({ showInBrowserTimeline = false, op, attributes }: SpanOptions = {}) =>
|
|
81
|
+
({ showInBrowserTimeline = false, showInRemoteTracing = true, op, attributes }: SpanOptions = {}) =>
|
|
80
82
|
(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<(...args: any) => any>) => {
|
|
81
83
|
const method = descriptor.value!;
|
|
82
84
|
|
|
83
85
|
descriptor.value = async function (this: any, ...args: any) {
|
|
84
|
-
const
|
|
86
|
+
const explicitCtx = args[0] instanceof Context ? args[0] : null;
|
|
87
|
+
|
|
85
88
|
const span = TRACE_PROCESSOR.traceSpan({
|
|
86
|
-
parentCtx,
|
|
89
|
+
parentCtx: explicitCtx,
|
|
87
90
|
methodName: propertyKey,
|
|
88
91
|
instance: this,
|
|
89
92
|
showInBrowserTimeline,
|
|
93
|
+
showInRemoteTracing,
|
|
90
94
|
op,
|
|
91
95
|
attributes,
|
|
92
96
|
});
|
|
93
97
|
|
|
94
|
-
const callArgs =
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
98
|
+
const callArgs = explicitCtx ? [span.ctx, ...args.slice(1)] : args;
|
|
99
|
+
|
|
100
|
+
return TRACE_PROCESSOR.remoteTracing.wrapExecution(span, async () => {
|
|
101
|
+
try {
|
|
102
|
+
return await method.apply(this, callArgs);
|
|
103
|
+
} catch (err) {
|
|
104
|
+
span.markError(err);
|
|
105
|
+
throw err;
|
|
106
|
+
} finally {
|
|
107
|
+
span.markSuccess();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
103
110
|
};
|
|
104
111
|
};
|
|
105
112
|
|
|
@@ -108,7 +115,7 @@ const spans = new Map<string, TracingSpan>();
|
|
|
108
115
|
/**
|
|
109
116
|
* Creates a span that must be ended manually.
|
|
110
117
|
*/
|
|
111
|
-
const spanStart = (params:
|
|
118
|
+
const spanStart = (params: TraceSpanProps & { id: string }) => {
|
|
112
119
|
if (spans.has(params.id)) {
|
|
113
120
|
return;
|
|
114
121
|
}
|
|
@@ -141,7 +148,7 @@ const addLink = (parent: any, child: any, opts: AddLinkOptions = {}) => {
|
|
|
141
148
|
TRACE_PROCESSOR.addLink(parent, child, opts);
|
|
142
149
|
};
|
|
143
150
|
|
|
144
|
-
export type
|
|
151
|
+
export type TraceDiagnosticProps<T> = {
|
|
145
152
|
/**
|
|
146
153
|
* Unique ID.
|
|
147
154
|
*/
|
|
@@ -167,7 +174,7 @@ export interface TraceDiagnostic {
|
|
|
167
174
|
/**
|
|
168
175
|
* Register a diagnostic that could be queried.
|
|
169
176
|
*/
|
|
170
|
-
const diagnostic = <T>(params:
|
|
177
|
+
const diagnostic = <T>(params: TraceDiagnosticProps<T>): TraceDiagnostic => {
|
|
171
178
|
return TRACE_PROCESSOR.diagnostics.registerDiagnostic(params);
|
|
172
179
|
};
|
|
173
180
|
|
package/src/diagnostic.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { asyncTimeout } from '@dxos/async';
|
|
6
6
|
import { invariant } from '@dxos/invariant';
|
|
7
7
|
|
|
8
|
-
import { type TraceDiagnostic, type
|
|
8
|
+
import { type TraceDiagnostic, type TraceDiagnosticProps } from './api';
|
|
9
9
|
import { createId } from './util';
|
|
10
10
|
|
|
11
11
|
export const DIAGNOSTICS_TIMEOUT = 10_000;
|
|
@@ -58,7 +58,7 @@ export class DiagnosticsManager {
|
|
|
58
58
|
this._instanceTag = tag;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
registerDiagnostic(params:
|
|
61
|
+
registerDiagnostic(params: TraceDiagnosticProps<any>): TraceDiagnostic {
|
|
62
62
|
const impl = new TraceDiagnosticImpl(params.id, params.fetch, params.name ?? params.id, () => {
|
|
63
63
|
if (this.registry.get(params.id) === impl) {
|
|
64
64
|
this.registry.delete(params.id);
|
package/src/remote/tracing.ts
CHANGED
|
@@ -6,48 +6,170 @@ import { type TracingSpan } from '../trace-processor';
|
|
|
6
6
|
|
|
7
7
|
type RemoteSpan = {
|
|
8
8
|
end: () => void;
|
|
9
|
+
/** Wraps execution so that this span becomes the active parent for child spans. */
|
|
10
|
+
wrapExecution?: <T>(fn: () => T) => T;
|
|
11
|
+
/** Opaque context object for the backend (e.g., OTEL Context with this span active). */
|
|
12
|
+
spanContext?: unknown;
|
|
9
13
|
};
|
|
10
14
|
|
|
11
15
|
export type StartSpanOptions = {
|
|
12
16
|
name: string;
|
|
13
17
|
op?: string;
|
|
14
18
|
attributes?: Record<string, any>;
|
|
19
|
+
/** Opaque parent context from a parent RemoteSpan (bridges async DXOS Context to OTEL). */
|
|
20
|
+
parentContext?: unknown;
|
|
15
21
|
};
|
|
16
22
|
|
|
17
23
|
interface TracingMethods {
|
|
18
24
|
startSpan: (options: StartSpanOptions) => RemoteSpan;
|
|
19
25
|
}
|
|
20
26
|
|
|
27
|
+
const MAX_ENDED_CONTEXTS = 10_000;
|
|
28
|
+
|
|
21
29
|
/**
|
|
22
30
|
* Allows traces to be recorded within SDK code without requiring specific consumers.
|
|
31
|
+
*
|
|
32
|
+
* Preserves OTEL span contexts after spans end so that long-lived DXOS Contexts
|
|
33
|
+
* (e.g., `this._ctx` stored during `open()`) can still serve as parents for
|
|
34
|
+
* later child spans and outbound trace-context injection.
|
|
23
35
|
*/
|
|
24
|
-
// TODO(wittjosiah): Should probably just use otel. Use `any` for now to not depend on Sentry directly.
|
|
25
36
|
export class RemoteTracing {
|
|
26
37
|
private _tracing: TracingMethods | undefined;
|
|
27
38
|
private _spanMap = new Map<TracingSpan, RemoteSpan>();
|
|
39
|
+
private _idToSpan = new Map<number, TracingSpan>();
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Retains OTEL span contexts after spans end so that periodic/background
|
|
43
|
+
* operations referencing a completed parent (via `this._ctx`) still produce
|
|
44
|
+
* correlated child spans instead of orphaned root traces.
|
|
45
|
+
*/
|
|
46
|
+
private _endedSpanContexts = new Map<number, unknown>();
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Buffers flushSpan calls that arrive before a processor is registered,
|
|
50
|
+
* so early startup spans are not silently dropped.
|
|
51
|
+
*/
|
|
52
|
+
private _pendingFlushes: Array<{ span: TracingSpan; isEnd: boolean }> | null = [];
|
|
28
53
|
|
|
29
54
|
registerProcessor(processor: TracingMethods): void {
|
|
30
55
|
this._tracing = processor;
|
|
56
|
+
|
|
57
|
+
const pending = this._pendingFlushes;
|
|
58
|
+
this._pendingFlushes = null;
|
|
59
|
+
if (pending) {
|
|
60
|
+
for (const { span, isEnd } of pending) {
|
|
61
|
+
this._replayFlush(span, isEnd);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Returns the opaque OTEL context for the given DXOS span ID, if one exists. */
|
|
67
|
+
getSpanContext(spanId: number): unknown | undefined {
|
|
68
|
+
const tracingSpan = this._idToSpan.get(spanId);
|
|
69
|
+
if (tracingSpan) {
|
|
70
|
+
return this._spanMap.get(tracingSpan)?.spanContext;
|
|
71
|
+
}
|
|
72
|
+
return this._endedSpanContexts.get(spanId);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Wraps execution so that the remote span is active as parent context. */
|
|
76
|
+
wrapExecution<T>(span: TracingSpan, fn: () => T): T {
|
|
77
|
+
const remoteSpan = this._spanMap.get(span);
|
|
78
|
+
if (remoteSpan?.wrapExecution) {
|
|
79
|
+
return remoteSpan.wrapExecution(fn);
|
|
80
|
+
}
|
|
81
|
+
return fn();
|
|
31
82
|
}
|
|
32
83
|
|
|
33
84
|
flushSpan(span: TracingSpan): void {
|
|
85
|
+
if (!span.showInRemoteTracing) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
34
89
|
if (!this._tracing) {
|
|
90
|
+
this._pendingFlushes?.push({ span, isEnd: !!span.endTs });
|
|
35
91
|
return;
|
|
36
92
|
}
|
|
37
93
|
|
|
38
94
|
if (!span.endTs) {
|
|
39
|
-
|
|
40
|
-
name: span.methodName,
|
|
41
|
-
op: span.op ?? 'function',
|
|
42
|
-
attributes: span.attributes,
|
|
43
|
-
});
|
|
44
|
-
this._spanMap.set(span, remoteSpan);
|
|
95
|
+
this._startRemoteSpan(span);
|
|
45
96
|
} else {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
97
|
+
this._endRemoteSpan(span);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private _startRemoteSpan(span: TracingSpan): void {
|
|
102
|
+
let parentContext: unknown;
|
|
103
|
+
if (span.parentId != null) {
|
|
104
|
+
const parentTracingSpan = this._idToSpan.get(span.parentId);
|
|
105
|
+
if (parentTracingSpan) {
|
|
106
|
+
parentContext = this._spanMap.get(parentTracingSpan)?.spanContext;
|
|
107
|
+
}
|
|
108
|
+
if (parentContext == null) {
|
|
109
|
+
parentContext = this._endedSpanContexts.get(span.parentId);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const attributes: Record<string, any> = {};
|
|
114
|
+
if (span.sanitizedClassName) {
|
|
115
|
+
attributes.entryPoint = span.sanitizedClassName;
|
|
116
|
+
}
|
|
117
|
+
for (const [key, value] of Object.entries(span.attributes)) {
|
|
118
|
+
attributes[key.startsWith('ctx.') ? key : `ctx.${key}`] = value;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const remoteSpan = this._tracing!.startSpan({
|
|
122
|
+
name: span.name,
|
|
123
|
+
op: span.op ?? 'function',
|
|
124
|
+
attributes,
|
|
125
|
+
parentContext,
|
|
126
|
+
});
|
|
127
|
+
this._spanMap.set(span, remoteSpan);
|
|
128
|
+
this._idToSpan.set(span.id, span);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private _endRemoteSpan(span: TracingSpan): void {
|
|
132
|
+
const remoteSpan = this._spanMap.get(span);
|
|
133
|
+
if (remoteSpan) {
|
|
134
|
+
if (remoteSpan.spanContext != null) {
|
|
135
|
+
this._endedSpanContexts.set(span.id, remoteSpan.spanContext);
|
|
136
|
+
this._evictEndedContexts();
|
|
137
|
+
}
|
|
138
|
+
remoteSpan.end();
|
|
139
|
+
this._spanMap.delete(span);
|
|
140
|
+
this._idToSpan.delete(span.id);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Replays a buffered flush that was queued before the processor was registered.
|
|
146
|
+
* For spans that started AND ended before registration, replays both events.
|
|
147
|
+
*/
|
|
148
|
+
private _replayFlush(span: TracingSpan, isEnd: boolean): void {
|
|
149
|
+
if (!isEnd) {
|
|
150
|
+
this._startRemoteSpan(span);
|
|
151
|
+
if (span.endTs != null) {
|
|
152
|
+
this._endRemoteSpan(span);
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
if (!this._spanMap.has(span)) {
|
|
156
|
+
this._startRemoteSpan(span);
|
|
157
|
+
}
|
|
158
|
+
this._endRemoteSpan(span);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private _evictEndedContexts(): void {
|
|
163
|
+
if (this._endedSpanContexts.size <= MAX_ENDED_CONTEXTS) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const iterator = this._endedSpanContexts.keys();
|
|
167
|
+
while (this._endedSpanContexts.size > MAX_ENDED_CONTEXTS) {
|
|
168
|
+
const oldest = iterator.next();
|
|
169
|
+
if (oldest.done) {
|
|
170
|
+
break;
|
|
50
171
|
}
|
|
172
|
+
this._endedSpanContexts.delete(oldest.value);
|
|
51
173
|
}
|
|
52
174
|
}
|
|
53
175
|
}
|
package/src/trace-processor.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { unrefTimeout } from '@dxos/async';
|
|
6
|
-
import {
|
|
6
|
+
import { Context } from '@dxos/context';
|
|
7
7
|
import { LogLevel, type LogProcessor, getContextFromEntry, log } from '@dxos/log';
|
|
8
8
|
import { type LogEntry } from '@dxos/protocols/proto/dxos/client/services';
|
|
9
9
|
import { type Error as SerializedError } from '@dxos/protocols/proto/dxos/error';
|
|
@@ -25,18 +25,19 @@ export type Diagnostics = {
|
|
|
25
25
|
logs: LogEntry[];
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
export type
|
|
28
|
+
export type TraceResourceConstructorProps = {
|
|
29
29
|
constructor: { new (...args: any[]): {} };
|
|
30
30
|
instance: any;
|
|
31
31
|
annotation?: symbol;
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
export type
|
|
34
|
+
export type TraceSpanProps = {
|
|
35
35
|
instance: any;
|
|
36
36
|
// TODO(wittjosiah): Rename to `name`.
|
|
37
37
|
methodName: string;
|
|
38
38
|
parentCtx: Context | null;
|
|
39
39
|
showInBrowserTimeline: boolean;
|
|
40
|
+
showInRemoteTracing?: boolean;
|
|
40
41
|
op?: string;
|
|
41
42
|
attributes?: Record<string, any>;
|
|
42
43
|
};
|
|
@@ -122,7 +123,7 @@ export class TraceProcessor {
|
|
|
122
123
|
* @internal
|
|
123
124
|
*/
|
|
124
125
|
// TODO(burdon): Comment.
|
|
125
|
-
createTraceResource(params:
|
|
126
|
+
createTraceResource(params: TraceResourceConstructorProps): void {
|
|
126
127
|
const id = this.resources.size;
|
|
127
128
|
|
|
128
129
|
// Init metrics counters.
|
|
@@ -158,7 +159,7 @@ export class TraceProcessor {
|
|
|
158
159
|
return new TraceSender(this);
|
|
159
160
|
}
|
|
160
161
|
|
|
161
|
-
traceSpan(params:
|
|
162
|
+
traceSpan(params: TraceSpanProps): TracingSpan {
|
|
162
163
|
const span = new TracingSpan(this, params);
|
|
163
164
|
this._flushSpan(span);
|
|
164
165
|
return span;
|
|
@@ -377,26 +378,27 @@ export class TracingSpan {
|
|
|
377
378
|
error: SerializedError | null = null;
|
|
378
379
|
|
|
379
380
|
private _showInBrowserTimeline: boolean;
|
|
380
|
-
private
|
|
381
|
+
private _showInRemoteTracing: boolean;
|
|
382
|
+
private readonly _ctx: Context;
|
|
381
383
|
|
|
382
384
|
constructor(
|
|
383
385
|
private _traceProcessor: TraceProcessor,
|
|
384
|
-
params:
|
|
386
|
+
params: TraceSpanProps,
|
|
385
387
|
) {
|
|
386
388
|
this.id = TracingSpan.nextId++;
|
|
387
389
|
this.methodName = params.methodName;
|
|
388
390
|
this.resourceId = _traceProcessor.getResourceId(params.instance);
|
|
389
391
|
this.startTs = performance.now();
|
|
390
392
|
this._showInBrowserTimeline = params.showInBrowserTimeline;
|
|
393
|
+
this._showInRemoteTracing = params.showInRemoteTracing ?? true;
|
|
391
394
|
this.op = params.op;
|
|
392
395
|
this.attributes = params.attributes ?? {};
|
|
393
396
|
|
|
397
|
+
const baseCtx = params.parentCtx ?? new Context();
|
|
398
|
+
this._ctx = this._showInRemoteTracing
|
|
399
|
+
? baseCtx.derive({ attributes: { [TRACE_SPAN_ATTRIBUTE]: this.id } })
|
|
400
|
+
: baseCtx.derive();
|
|
394
401
|
if (params.parentCtx) {
|
|
395
|
-
this._ctx = params.parentCtx.derive({
|
|
396
|
-
attributes: {
|
|
397
|
-
[TRACE_SPAN_ATTRIBUTE]: this.id,
|
|
398
|
-
},
|
|
399
|
-
});
|
|
400
402
|
const parentId = params.parentCtx.getAttribute(TRACE_SPAN_ATTRIBUTE);
|
|
401
403
|
if (typeof parentId === 'number') {
|
|
402
404
|
this.parentId = parentId;
|
|
@@ -409,10 +411,20 @@ export class TracingSpan {
|
|
|
409
411
|
return resource ? `${resource.sanitizedClassName}#${resource.data.instanceId}.${this.methodName}` : this.methodName;
|
|
410
412
|
}
|
|
411
413
|
|
|
412
|
-
|
|
414
|
+
/** Sanitized class name of the owning resource, if available. */
|
|
415
|
+
get sanitizedClassName(): string | undefined {
|
|
416
|
+
const resource = this.resourceId != null ? this._traceProcessor.resources.get(this.resourceId) : undefined;
|
|
417
|
+
return resource?.sanitizedClassName;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
get ctx(): Context {
|
|
413
421
|
return this._ctx;
|
|
414
422
|
}
|
|
415
423
|
|
|
424
|
+
get showInRemoteTracing(): boolean {
|
|
425
|
+
return this._showInRemoteTracing;
|
|
426
|
+
}
|
|
427
|
+
|
|
416
428
|
markSuccess(): void {
|
|
417
429
|
this.endTs = performance.now();
|
|
418
430
|
this._traceProcessor._flushSpan(this);
|
|
@@ -537,13 +549,13 @@ const areEqualShallow = (a: any, b: any) => {
|
|
|
537
549
|
};
|
|
538
550
|
|
|
539
551
|
export const sanitizeClassName = (className: string) => {
|
|
552
|
+
let name = className.replace(/^_+/, '');
|
|
540
553
|
const SANITIZE_REGEX = /[^_](\d+)$/;
|
|
541
|
-
const m =
|
|
542
|
-
if (
|
|
543
|
-
|
|
544
|
-
} else {
|
|
545
|
-
return className.slice(0, -m[1].length);
|
|
554
|
+
const m = name.match(SANITIZE_REGEX);
|
|
555
|
+
if (m) {
|
|
556
|
+
name = name.slice(0, -m[1].length);
|
|
546
557
|
}
|
|
558
|
+
return name;
|
|
547
559
|
};
|
|
548
560
|
|
|
549
561
|
const isSetLike = (value: any): value is Set<any> =>
|