Skip to content

Commit 47b89b1

Browse files
committed
align with previous code
1 parent 4e0c670 commit 47b89b1

File tree

1 file changed

+72
-63
lines changed

1 file changed

+72
-63
lines changed

packages/browser/src/profiling/UIProfiler.ts

Lines changed: 72 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,14 @@ export class UIProfiler {
6363

6464
/** Initialize the profiler with client, session sampling and lifecycle mode. */
6565
public initialize(client: Client, sessionSampled: boolean, lifecycleMode: 'manual' | 'trace'): void {
66-
this._client = client;
67-
this._sessionSampled = sessionSampled;
68-
this._lifecycleMode = lifecycleMode;
69-
70-
// One profiler ID for the entire profiling session (user session)
7166
this._profilerId = uuid4();
7267

7368
DEBUG_BUILD && debug.log(`[Profiling] Initializing profiler (lifecycle='${lifecycleMode}').`);
7469

70+
this._client = client;
71+
this._sessionSampled = sessionSampled;
72+
this._lifecycleMode = lifecycleMode;
73+
7574
if (!sessionSampled) {
7675
DEBUG_BUILD && debug.log('[Profiling] Session not sampled; profiler will remain inactive.');
7776
}
@@ -118,33 +117,42 @@ export class UIProfiler {
118117
this._endProfiling();
119118
}
120119

121-
/** Notify the profiler of a root span active at setup time (used only in trace mode). */
120+
/** Handle an already-active root span at integration setup time (used only in trace mode). */
122121
public notifyRootSpanActive(span: Span): void {
123122
if (this._lifecycleMode !== 'trace' || !this._sessionSampled) {
124123
return;
125124
}
125+
126126
const spanId = span.spanContext().spanId;
127127
if (!spanId || this._activeRootSpanIds.has(spanId)) {
128128
return;
129129
}
130130
this._registerTraceRootSpan(spanId);
131-
}
132131

133-
/* ========================= Internal Helpers ========================= */
132+
const rootSpanCount = this._activeRootSpanIds.size;
133+
134+
if (rootSpanCount === 1) {
135+
DEBUG_BUILD &&
136+
debug.log('[Profiling] Detected already active root span during setup. Active root spans now:', rootSpanCount);
137+
138+
this._beginProfiling();
139+
}
140+
}
134141

135-
/** Begin profiling session (shared path used by manual start or trace activation). */
142+
/** Begin profiling if not already running. */
136143
private _beginProfiling(): void {
137144
if (this._isRunning) {
138145
return;
139146
}
140147
this._isRunning = true;
141148

142-
// Expose profiler_id so emitted events can be associated
143-
getGlobalScope().setContext('profile', { profiler_id: this._profilerId });
144-
145149
DEBUG_BUILD && debug.log('[Profiling] Started profiling with profiler ID:', this._profilerId);
146150

151+
// Expose profiler_id to match root spans with profiles
152+
getGlobalScope().setContext('profile', { profiler_id: this._profilerId });
153+
147154
this._startProfilerInstance();
155+
148156
if (!this._profiler) {
149157
DEBUG_BUILD && debug.log('[Profiling] Failed to start JS Profiler; stopping.');
150158
this._resetProfilerInfo();
@@ -154,7 +162,7 @@ export class UIProfiler {
154162
this._startPeriodicChunking();
155163
}
156164

157-
/** End profiling session, collect final chunk. */
165+
/** End profiling session; final chunk will be collected and sent. */
158166
private _endProfiling(): void {
159167
if (!this._isRunning) {
160168
return;
@@ -166,51 +174,51 @@ export class UIProfiler {
166174
this._chunkTimer = undefined;
167175
}
168176

169-
// Clear trace-mode timeouts if any
170177
this._clearAllRootSpanTimeouts();
171178

172179
this._collectCurrentChunk().catch(e => {
173180
DEBUG_BUILD && debug.error('[Profiling] Failed to collect current profile chunk on stop():', e);
174181
});
175182

176-
// Clear context so subsequent events aren't marked as profiled
177-
getGlobalScope().setContext('profile', {});
183+
// Clear context so subsequent events aren't marked as profiled in manual mode.
184+
// todo: test in manual mode
185+
if (this._lifecycleMode === 'manual') {
186+
getGlobalScope().setContext('profile', {});
187+
}
178188
}
179189

180190
/** Trace-mode: attach spanStart/spanEnd listeners. */
181191
private _setupTraceLifecycleListeners(client: Client): void {
182192
client.on('spanStart', span => {
183193
if (!this._sessionSampled) {
184-
DEBUG_BUILD && debug.log('[Profiling] Session not sampled; ignoring spanStart.');
194+
DEBUG_BUILD && debug.log('[Profiling] Session not sampled because of negative sampling decision.');
185195
return;
186196
}
187197
if (span !== getRootSpan(span)) {
188198
return; // only care about root spans
189199
}
190200
// Only count sampled root spans
191201
if (!span.isRecording()) {
192-
DEBUG_BUILD && debug.log('[Profiling] Ignoring non-sampled root span.');
202+
DEBUG_BUILD && debug.log('[Profiling] Discarding profile because root span was not sampled.');
193203
return;
194204
}
195205

196-
/*
197-
// Matching root spans with profiles
198-
getGlobalScope().setContext('profile', {
199-
profiler_id: this._profilerId,
200-
});
201-
*/
206+
// Match emitted chunks with events: set profiler_id on global scope
207+
// do I need this?
208+
// getGlobalScope().setContext('profile', { profiler_id: this._profilerId });
202209

203210
const spanId = span.spanContext().spanId;
204211
if (!spanId || this._activeRootSpanIds.has(spanId)) {
205212
return;
206213
}
214+
207215
this._registerTraceRootSpan(spanId);
208216

209-
const count = this._activeRootSpanIds.size;
210-
if (count === 1) {
217+
const rootSpanCount = this._activeRootSpanIds.size;
218+
if (rootSpanCount === 1) {
211219
DEBUG_BUILD &&
212220
debug.log(
213-
`[Profiling] Root span ${spanId} started. Profiling active while there are active root spans (count=${count}).`,
221+
`[Profiling] Root span ${spanId} started. Profiling active while there are active root spans (count=${rootSpanCount}).`,
214222
);
215223
this._beginProfiling();
216224
}
@@ -225,46 +233,25 @@ export class UIProfiler {
225233
return;
226234
}
227235
this._activeRootSpanIds.delete(spanId);
236+
const rootSpanCount = this._activeRootSpanIds.size;
228237

229-
const count = this._activeRootSpanIds.size;
230-
DEBUG_BUILD && debug.log(`[Profiling] Root span ${spanId} ended. Remaining active root spans (count=${count}).`);
231-
232-
if (count === 0) {
233-
// Collect final chunk before stopping
238+
DEBUG_BUILD &&
239+
debug.log(
240+
`[Profiling] Root span with ID ${spanId} ended. Will continue profiling for as long as there are active root spans (currently: ${rootSpanCount}).`,
241+
);
242+
if (rootSpanCount === 0) {
234243
this._collectCurrentChunk().catch(e => {
235-
DEBUG_BUILD && debug.error('[Profiling] Failed to collect current profile chunk on last spanEnd:', e);
244+
DEBUG_BUILD && debug.error('[Profiling] Failed to collect current profile chunk on last `spanEnd`:', e);
236245
});
237246
this._endProfiling();
238247
}
239248
});
240249
}
241250

242-
/** Register root span and schedule safeguard timeout (trace mode). */
243-
private _registerTraceRootSpan(spanId: string): void {
244-
this._activeRootSpanIds.add(spanId);
245-
const timeout = setTimeout(() => this._onRootSpanTimeout(spanId), MAX_ROOT_SPAN_PROFILE_MS);
246-
this._rootSpanTimeouts.set(spanId, timeout);
247-
}
248-
249-
/** Root span timeout handler (trace mode). */
250-
private _onRootSpanTimeout(spanId: string): void {
251-
if (!this._rootSpanTimeouts.has(spanId)) {
252-
return; // span already ended
253-
}
254-
this._rootSpanTimeouts.delete(spanId);
255-
256-
if (!this._activeRootSpanIds.has(spanId)) {
257-
return;
258-
}
259-
260-
DEBUG_BUILD &&
261-
debug.log(`[Profiling] Reached 5-minute timeout for root span ${spanId}. Did you forget to call .end()?`);
262-
263-
this._activeRootSpanIds.delete(spanId);
264-
265-
if (this._activeRootSpanIds.size === 0) {
266-
this._endProfiling();
267-
}
251+
/** Reset running state and profiling context (used on failure). */
252+
private _resetProfilerInfo(): void {
253+
this._isRunning = false;
254+
getGlobalScope().setContext('profile', {});
268255
}
269256

270257
/** Clear all trace-mode root span timeouts. */
@@ -273,10 +260,11 @@ export class UIProfiler {
273260
this._rootSpanTimeouts.clear();
274261
}
275262

276-
/** Reset running state and profiling context (used on failure). */
277-
private _resetProfilerInfo(): void {
278-
this._isRunning = false;
279-
getGlobalScope().setContext('profile', {});
263+
/** Register root span and schedule safeguard timeout (trace mode). */
264+
private _registerTraceRootSpan(spanId: string): void {
265+
this._activeRootSpanIds.add(spanId);
266+
const timeout = setTimeout(() => this._onRootSpanTimeout(spanId), MAX_ROOT_SPAN_PROFILE_MS);
267+
this._rootSpanTimeouts.set(spanId, timeout);
280268
}
281269

282270
/** Start JS self profiler instance if needed. */
@@ -315,6 +303,27 @@ export class UIProfiler {
315303
}, CHUNK_INTERVAL_MS);
316304
}
317305

306+
/** Root span timeout handler (trace mode). */
307+
private _onRootSpanTimeout(spanId: string): void {
308+
if (!this._rootSpanTimeouts.has(spanId)) {
309+
return; // span already ended
310+
}
311+
this._rootSpanTimeouts.delete(spanId);
312+
313+
if (!this._activeRootSpanIds.has(spanId)) {
314+
return;
315+
}
316+
317+
DEBUG_BUILD &&
318+
debug.log(`[Profiling] Reached 5-minute timeout for root span ${spanId}. Did you forget to call .end()?`);
319+
320+
this._activeRootSpanIds.delete(spanId);
321+
322+
if (this._activeRootSpanIds.size === 0) {
323+
this._endProfiling();
324+
}
325+
}
326+
318327
/** Stop current profiler instance, convert profile to chunk & send. */
319328
private async _collectCurrentChunk(): Promise<void> {
320329
const prev = this._profiler;

0 commit comments

Comments
 (0)