Skip to content

Commit d8919a0

Browse files
authored
[Flight] Log "Server Requests" Track (#33394)
Stacked on #33392. This adds another track to the Performance Track called `"Server Requests"`. <img width="1015" alt="Screenshot 2025-06-01 at 12 02 14 AM" src="https://github.com/user-attachments/assets/c4d164c4-cfdf-4e14-9a87-3f011f65fd20" /> This logs the flat list of I/O awaited on by Server Components. There will be other views that are more focused on what data blocks a specific Component or Suspense boundary but this is just the list of all the I/O basically so you can get an overview of those waterfalls without the noise of all the Component trees and rendering. It's similar to what the "Network" track is on the client. I've been going back and forth on what to call this track but I went with `"Server Requests"` for now. The idea is that the name should communicate that this is something that happens on the server and is a pairing with the `"Server Components"` track. Although we don't use that feature, since it's missing granularity, it's also similar to "Server Timings".
1 parent 2e9f8cd commit d8919a0

File tree

2 files changed

+67
-3
lines changed

2 files changed

+67
-3
lines changed

packages/react-client/src/ReactFlightClient.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ import {
7878
logComponentRender,
7979
logDedupedComponentRender,
8080
logComponentErrored,
81+
logIOInfo,
8182
} from './ReactFlightPerformanceTrack';
8283

8384
import {
@@ -2769,6 +2770,8 @@ function initializeIOInfo(response: Response, ioInfo: ReactIOInfo): void {
27692770
ioInfo.start += response._timeOrigin;
27702771
// $FlowFixMe[cannot-write]
27712772
ioInfo.end += response._timeOrigin;
2773+
2774+
logIOInfo(ioInfo);
27722775
}
27732776

27742777
function resolveIOInfo(
@@ -2890,6 +2893,7 @@ function flushComponentPerformance(
28902893
trackIdx,
28912894
parentEndTime,
28922895
previousEndTime,
2896+
response._rootEnvironmentName,
28932897
);
28942898
}
28952899
// Since we didn't bump the track this time, we just return the same track.

packages/react-client/src/ReactFlightPerformanceTrack.js

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
/* eslint-disable react-internal/no-production-logging */
1111

12-
import type {ReactComponentInfo} from 'shared/ReactTypes';
12+
import type {ReactComponentInfo, ReactIOInfo} from 'shared/ReactTypes';
1313

1414
import {enableProfilerTimer} from 'shared/ReactFeatureFlags';
1515

@@ -18,13 +18,22 @@ const supportsUserTiming =
1818
typeof console !== 'undefined' &&
1919
typeof console.timeStamp === 'function';
2020

21+
const IO_TRACK = 'Server Requests ⚛';
2122
const COMPONENTS_TRACK = 'Server Components ⚛';
2223

2324
export function markAllTracksInOrder() {
2425
if (supportsUserTiming) {
2526
// Ensure we create the Server Component track groups earlier than the Client Scheduler
2627
// and Client Components. We can always add the 0 time slot even if it's in the past.
2728
// That's still considered for ordering.
29+
console.timeStamp(
30+
'Server Requests Track',
31+
0.001,
32+
0.001,
33+
IO_TRACK,
34+
undefined,
35+
'primary-light',
36+
);
2837
console.timeStamp(
2938
'Server Components Track',
3039
0.001,
@@ -166,9 +175,13 @@ export function logDedupedComponentRender(
166175
trackIdx: number,
167176
startTime: number,
168177
endTime: number,
178+
rootEnv: string,
169179
): void {
170180
if (supportsUserTiming && endTime >= 0 && trackIdx < 10) {
181+
const env = componentInfo.env;
171182
const name = componentInfo.name;
183+
const isPrimaryEnv = env === rootEnv;
184+
const color = isPrimaryEnv ? 'primary-light' : 'secondary-light';
172185
const entryName = name + ' [deduped]';
173186
const debugTask = componentInfo.debugTask;
174187
if (__DEV__ && debugTask) {
@@ -181,7 +194,7 @@ export function logDedupedComponentRender(
181194
endTime,
182195
trackNames[trackIdx],
183196
COMPONENTS_TRACK,
184-
'tertiary-light',
197+
color,
185198
),
186199
);
187200
} else {
@@ -191,7 +204,54 @@ export function logDedupedComponentRender(
191204
endTime,
192205
trackNames[trackIdx],
193206
COMPONENTS_TRACK,
194-
'tertiary-light',
207+
color,
208+
);
209+
}
210+
}
211+
}
212+
213+
function getIOColor(
214+
functionName: string,
215+
): 'tertiary-light' | 'tertiary' | 'tertiary-dark' {
216+
// Add some color variation to be able to distinguish various sources.
217+
switch (functionName.charCodeAt(0) % 3) {
218+
case 0:
219+
return 'tertiary-light';
220+
case 1:
221+
return 'tertiary';
222+
default:
223+
return 'tertiary-dark';
224+
}
225+
}
226+
227+
export function logIOInfo(ioInfo: ReactIOInfo): void {
228+
const startTime = ioInfo.start;
229+
const endTime = ioInfo.end;
230+
if (supportsUserTiming && endTime >= 0) {
231+
const name = ioInfo.name;
232+
const debugTask = ioInfo.debugTask;
233+
const color = getIOColor(name);
234+
if (__DEV__ && debugTask) {
235+
debugTask.run(
236+
// $FlowFixMe[method-unbinding]
237+
console.timeStamp.bind(
238+
console,
239+
name,
240+
startTime < 0 ? 0 : startTime,
241+
endTime,
242+
IO_TRACK,
243+
undefined,
244+
color,
245+
),
246+
);
247+
} else {
248+
console.timeStamp(
249+
name,
250+
startTime < 0 ? 0 : startTime,
251+
endTime,
252+
IO_TRACK,
253+
undefined,
254+
color,
195255
);
196256
}
197257
}

0 commit comments

Comments
 (0)