Skip to content

Commit 5f34b05

Browse files
authored
[Devtools] add logs for profiler tab switch & settings change (#24966)
* [devtools] add logs for profiler tab switch & settings change * prettier * remove unnecessary console.log * better naming: logEvent -> loggerEvent * use same object for event and metadata
1 parent b66936e commit 5f34b05

File tree

8 files changed

+96
-20
lines changed

8 files changed

+96
-20
lines changed

packages/react-devtools-shared/src/Logger.js

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

1010
import {enableLogger} from 'react-devtools-feature-flags';
1111

12-
export type LogEvent =
12+
export type LoggerEvent =
1313
| {|
1414
+event_name: 'loaded-dev-tools',
1515
|}
@@ -34,22 +34,42 @@ export type LogEvent =
3434
|}
3535
| {|
3636
+event_name: 'select-element',
37+
+metadata: {
38+
+source: string,
39+
},
3740
|}
3841
| {|
3942
+event_name: 'inspect-element-button-clicked',
4043
|}
4144
| {|
4245
+event_name: 'profiling-start',
46+
+metadata: {
47+
+current_tab: string,
48+
},
49+
|}
50+
| {|
51+
+event_name: 'profiler-tab-changed',
52+
+metadata: {
53+
+tabId: string,
54+
},
55+
|}
56+
| {|
57+
+event_name: 'settings-changed',
58+
+metadata: {
59+
+key: string,
60+
+value: any,
61+
...
62+
},
4363
|};
4464

45-
export type LogFunction = (LogEvent, ?Object) => void | Promise<void>;
65+
export type LogFunction = LoggerEvent => void | Promise<void>;
4666

4767
let logFunctions: Array<LogFunction> = [];
4868
export const logEvent: LogFunction =
4969
enableLogger === true
50-
? function logEvent(event: LogEvent, metadata: ?Object): void {
70+
? function logEvent(event: LoggerEvent): void {
5171
logFunctions.forEach(log => {
52-
log(event, metadata);
72+
log(event);
5373
});
5474
}
5575
: function logEvent() {};

packages/react-devtools-shared/src/devtools/views/Components/Element.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ export default function Element({data, index, style}: Props) {
7777

7878
const handleClick = ({metaKey}) => {
7979
if (id !== null) {
80-
logEvent({event_name: 'select-element'}, {source: 'click-element'});
80+
logEvent({
81+
event_name: 'select-element',
82+
metadata: {source: 'click-element'},
83+
});
8184
dispatch({
8285
type: 'SELECT_ELEMENT_BY_ID',
8386
payload: metaKey ? null : id,

packages/react-devtools-shared/src/devtools/views/Components/InspectedElementView.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,10 @@ function OwnerView({
303303
} = useHighlightNativeElement();
304304

305305
const handleClick = useCallback(() => {
306-
logEvent({event_name: 'select-element'}, {source: 'owner-view'});
306+
logEvent({
307+
event_name: 'select-element',
308+
metadata: {source: 'owner-view'},
309+
});
307310
dispatch({
308311
type: 'SELECT_ELEMENT_BY_ID',
309312
payload: id,

packages/react-devtools-shared/src/devtools/views/Components/Tree.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ export default function Tree(props: Props) {
104104
function handleStopInspectingNative(didSelectNode) {
105105
if (didSelectNode && focusTargetRef.current !== null) {
106106
focusTargetRef.current.focus();
107-
logEvent({event_name: 'select-element'}, {source: 'inspector'});
107+
logEvent({
108+
event_name: 'select-element',
109+
metadata: {source: 'inspector'},
110+
});
108111
}
109112
}
110113
bridge.addListener('stopInspectingNative', handleStopInspectingNative);

packages/react-devtools-shared/src/devtools/views/Profiler/ProfilerContext.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,21 @@ function ProfilerContextController({children}: Props) {
207207
const [selectedTabID, selectTab] = useLocalStorage<TabID>(
208208
'React::DevTools::Profiler::defaultTab',
209209
'flame-chart',
210+
value => {
211+
logEvent({
212+
event_name: 'profiler-tab-changed',
213+
metadata: {
214+
tabId: value,
215+
},
216+
});
217+
},
210218
);
211219

212220
const startProfiling = useCallback(() => {
213-
logEvent({event_name: 'profiling-start'}, {current_tab: selectedTabID});
221+
logEvent({
222+
event_name: 'profiling-start',
223+
metadata: {current_tab: selectedTabID},
224+
});
214225
store.profilerStore.startProfiling();
215226
}, [store, selectedTabID]);
216227
const stopProfiling = useCallback(() => store.profilerStore.stopProfiling(), [

packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
} from 'react-devtools-shared/src/constants';
2828
import {useLocalStorage} from '../hooks';
2929
import {BridgeContext} from '../context';
30+
import {logEvent} from 'react-devtools-shared/src/Logger';
3031

3132
import type {BrowserTheme} from '../DevTools';
3233

@@ -68,6 +69,22 @@ type Context = {|
6869
const SettingsContext = createContext<Context>(((null: any): Context));
6970
SettingsContext.displayName = 'SettingsContext';
7071

72+
function useLocalStorageWithLog<T>(
73+
key: string,
74+
initialValue: T | (() => T),
75+
): [T, (value: T | (() => T)) => void] {
76+
return useLocalStorage<T>(key, initialValue, (v, k) => {
77+
logEvent({
78+
event_name: 'settings-changed',
79+
metadata: {
80+
source: 'localStorage setter',
81+
key: k,
82+
value: v,
83+
},
84+
});
85+
});
86+
}
87+
7188
type DocumentElements = Array<HTMLElement>;
7289

7390
type Props = {|
@@ -85,47 +102,56 @@ function SettingsContextController({
85102
}: Props) {
86103
const bridge = useContext(BridgeContext);
87104

88-
const [displayDensity, setDisplayDensity] = useLocalStorage<DisplayDensity>(
105+
const [
106+
displayDensity,
107+
setDisplayDensity,
108+
] = useLocalStorageWithLog<DisplayDensity>(
89109
'React::DevTools::displayDensity',
90110
'compact',
91111
);
92-
const [theme, setTheme] = useLocalStorage<Theme>(
112+
const [theme, setTheme] = useLocalStorageWithLog<Theme>(
93113
'React::DevTools::theme',
94114
'auto',
95115
);
96116
const [
97117
appendComponentStack,
98118
setAppendComponentStack,
99-
] = useLocalStorage<boolean>(LOCAL_STORAGE_SHOULD_PATCH_CONSOLE_KEY, true);
119+
] = useLocalStorageWithLog<boolean>(
120+
LOCAL_STORAGE_SHOULD_PATCH_CONSOLE_KEY,
121+
true,
122+
);
100123
const [
101124
breakOnConsoleErrors,
102125
setBreakOnConsoleErrors,
103-
] = useLocalStorage<boolean>(
126+
] = useLocalStorageWithLog<boolean>(
104127
LOCAL_STORAGE_SHOULD_BREAK_ON_CONSOLE_ERRORS,
105128
false,
106129
);
107-
const [parseHookNames, setParseHookNames] = useLocalStorage<boolean>(
130+
const [parseHookNames, setParseHookNames] = useLocalStorageWithLog<boolean>(
108131
LOCAL_STORAGE_PARSE_HOOK_NAMES_KEY,
109132
false,
110133
);
111134
const [
112135
hideConsoleLogsInStrictMode,
113136
sethideConsoleLogsInStrictMode,
114-
] = useLocalStorage<boolean>(
137+
] = useLocalStorageWithLog<boolean>(
115138
LOCAL_STORAGE_HIDE_CONSOLE_LOGS_IN_STRICT_MODE,
116139
false,
117140
);
118141
const [
119142
showInlineWarningsAndErrors,
120143
setShowInlineWarningsAndErrors,
121-
] = useLocalStorage<boolean>(
144+
] = useLocalStorageWithLog<boolean>(
122145
LOCAL_STORAGE_SHOW_INLINE_WARNINGS_AND_ERRORS_KEY,
123146
true,
124147
);
125148
const [
126149
traceUpdatesEnabled,
127150
setTraceUpdatesEnabled,
128-
] = useLocalStorage<boolean>(LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY, false);
151+
] = useLocalStorageWithLog<boolean>(
152+
LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY,
153+
false,
154+
);
129155

130156
const documentElements = useMemo<DocumentElements>(() => {
131157
const array: Array<HTMLElement> = [

packages/react-devtools-shared/src/devtools/views/hooks.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ export function useIsOverflowing(
144144
export function useLocalStorage<T>(
145145
key: string,
146146
initialValue: T | (() => T),
147+
onValueSet?: (any, string) => void,
147148
): [T, (value: T | (() => T)) => void] {
148149
const getValueFromLocalStorage = useCallback(() => {
149150
try {
@@ -173,6 +174,10 @@ export function useLocalStorage<T>(
173174

174175
// Notify listeners that this setting has changed.
175176
window.dispatchEvent(new Event(key));
177+
178+
if (onValueSet != null) {
179+
onValueSet(valueToStore, key);
180+
}
176181
} catch (error) {
177182
console.log(error);
178183
}

packages/react-devtools-shared/src/registerDevToolsEventLogger.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @flow strict-local
88
*/
99

10-
import type {LogEvent} from 'react-devtools-shared/src/Logger';
10+
import type {LoggerEvent} from 'react-devtools-shared/src/Logger';
1111

1212
import {registerEventLogger} from 'react-devtools-shared/src/Logger';
1313
import {enableLogger} from 'react-devtools-feature-flags';
@@ -25,17 +25,22 @@ export function registerDevToolsEventLogger(
2525
| LoggerContext
2626
| ?(() => Promise<LoggerContext>),
2727
): void {
28-
async function logEvent(event: LogEvent, metadata: ?Object) {
28+
async function logEvent(event: LoggerEvent) {
2929
if (enableLogger) {
3030
if (loggingIFrame != null) {
31+
let metadata = null;
32+
if (event.metadata != null) {
33+
metadata = event.metadata;
34+
delete event.metadata;
35+
}
3136
loggingIFrame.contentWindow.postMessage(
3237
{
3338
source: 'react-devtools-logging',
3439
event: event,
3540
context: {
3641
surface,
3742
version: process.env.DEVTOOLS_VERSION,
38-
metadata: metadata != null ? JSON.stringify(metadata) : '',
43+
metadata: metadata !== null ? JSON.stringify(metadata) : '',
3944
...(fetchAdditionalContext != null
4045
? await fetchAdditionalContext()
4146
: {}),
@@ -56,7 +61,7 @@ export function registerDevToolsEventLogger(
5661

5762
loggingIFrame = iframe;
5863
if (missedEvents.length > 0) {
59-
missedEvents.forEach(logEvent);
64+
missedEvents.forEach(event => logEvent(event));
6065
missedEvents = [];
6166
}
6267
}

0 commit comments

Comments
 (0)