Skip to content

Commit 96e6bb8

Browse files
authored
feat: use scoped field in trace events to propagate stack traces (#213)
1 parent 54afd87 commit 96e6bb8

File tree

3 files changed

+63
-11
lines changed

3 files changed

+63
-11
lines changed

front_end/models/trace/extras/StackTraceForEvent.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,46 @@ export function get(event: Types.Events.Event, parsedTrace: Handlers.Types.Parse
5050
return result;
5151
}
5252

53+
export function getForReactNative(event: Types.Events.Event, parsedTrace: Handlers.Types.ParsedTrace): Protocol.Runtime.StackTrace |
54+
null {
55+
let cacheForTrace = stackTraceForEventInTrace.get(parsedTrace);
56+
if (!cacheForTrace) {
57+
cacheForTrace = new Map();
58+
stackTraceForEventInTrace.set(parsedTrace, cacheForTrace);
59+
}
60+
const resultFromCache = cacheForTrace.get(event);
61+
if (resultFromCache) {
62+
return resultFromCache;
63+
}
64+
let result: Protocol.Runtime.StackTrace|null = null;
65+
66+
if (Types.Events.isUserTiming(event) && Types.Events.isPerformanceMeasureBegin(event)) {
67+
result = extractStackTraceForReactNative(event);
68+
} else if (Types.Extensions.isSyntheticExtensionEntry(event)) {
69+
result = extractStackTraceForReactNative(event.rawSourceEvent);
70+
} else if (Types.Events.isConsoleTimeStamp(event)) {
71+
result = extractStackTraceForReactNative(event);
72+
}
73+
74+
if (result) {
75+
cacheForTrace.set(event, result);
76+
}
77+
return result;
78+
}
79+
80+
export function extractStackTraceForReactNative(event: Types.Events.Event): Protocol.Runtime.StackTrace | null {
81+
const data = event.args?.data;
82+
if (!data) {
83+
return null;
84+
}
85+
86+
if (!data.rnStackTrace) {
87+
return null;
88+
}
89+
90+
return data.rnStackTrace;
91+
}
92+
5393
function getForProfileCall(
5494
event: Types.Events.SyntheticProfileCall, parsedTrace: Handlers.Types.ParsedTrace): Protocol.Runtime.StackTrace {
5595
// When working with a CPU profile the renderer handler won't have

front_end/models/trace/types/TraceEvents.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ export interface Args {
9393

9494
export interface ArgsData {
9595
stackTrace?: CallFrame[];
96+
// [RN] Custom field for linking stack traces to User Timings and TimeStamp events.
97+
rnStackTrace?: Protocol.Runtime.StackTrace;
9698
sampleTraceId?: number;
9799
url?: string;
98100
navigationId?: string;

front_end/panels/timeline/TimelineUIUtils.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,22 +1838,32 @@ export class TimelineUIUtils {
18381838
const {startTime} = Trace.Helpers.Timing.eventTimingsMilliSeconds(event);
18391839
let initiatorStackLabel = i18nString(UIStrings.initiatorStackTrace);
18401840
let stackLabel = i18nString(UIStrings.stackTrace);
1841-
const stackTraceForEvent = Trace.Extras.StackTraceForEvent.get(event, parsedTrace);
1841+
18421842
// [RN] Used to scope down available features for React Native targets
18431843
// See https://docs.google.com/document/d/1_mtLIHEd9bFQN4xWBSVDR357GaRo56khB1aOxgWDeu4/edit?tab=t.0 for context.
18441844
const isReactNative = Root.Runtime.experiments.isEnabled(
18451845
Root.Runtime.ExperimentName.REACT_NATIVE_SPECIFIC_UI,
18461846
);
1847-
if (stackTraceForEvent && !isReactNative) {
1848-
contentHelper.addSection(i18nString(UIStrings.stackTrace));
1849-
contentHelper.createChildStackTraceElement(stackTraceForEvent);
1850-
// TODO(andoli): also build stack trace component for other events
1851-
// that have a stack trace using the StackTraceForEvent helper.
1852-
} else if (!isReactNative) {
1853-
const stackTrace = Trace.Helpers.Trace.getZeroIndexedStackTraceForEvent(event);
1854-
if (stackTrace?.length) {
1855-
contentHelper.addSection(stackLabel);
1856-
contentHelper.createChildStackTraceElement(TimelineUIUtils.stackTraceFromCallFrames(stackTrace));
1847+
if (isReactNative) {
1848+
const rnStackTrace = Trace.Extras.StackTraceForEvent.getForReactNative(event, parsedTrace);
1849+
1850+
if (rnStackTrace) {
1851+
contentHelper.addSection(i18nString(UIStrings.stackTrace));
1852+
contentHelper.createChildStackTraceElement(rnStackTrace);
1853+
}
1854+
} else {
1855+
const stackTraceForEvent = Trace.Extras.StackTraceForEvent.get(event, parsedTrace);
1856+
if (stackTraceForEvent) {
1857+
contentHelper.addSection(i18nString(UIStrings.stackTrace));
1858+
contentHelper.createChildStackTraceElement(stackTraceForEvent);
1859+
// TODO(andoli): also build stack trace component for other events
1860+
// that have a stack trace using the StackTraceForEvent helper.
1861+
} else {
1862+
const stackTrace = Trace.Helpers.Trace.getZeroIndexedStackTraceForEvent(event);
1863+
if (stackTrace?.length) {
1864+
contentHelper.addSection(stackLabel);
1865+
contentHelper.createChildStackTraceElement(TimelineUIUtils.stackTraceFromCallFrames(stackTrace));
1866+
}
18571867
}
18581868
}
18591869
switch (event.name) {

0 commit comments

Comments
 (0)