[DevTools] Extension reports logged events when feature flag is enabled (#22475)
Juan committed
Sep 30, 2021 at 13:47 UTC
75b9869648a2043d8c42693f44db437f40ea7d38
5 files changed
+96
-24
packages/react-devtools-extensions/src/main.js
+2
-4
@@ -18,9 +18,9 @@ import {
18
localStorageRemoveItem,
19
localStorageSetItem,
20
} from 'react-devtools-shared/src/storage';
21
-import {registerEventLogger} from 'react-devtools-shared/src/Logger';
21
import DevTools from 'react-devtools-shared/src/devtools/views/DevTools';
22
import {__DEBUG__} from 'react-devtools-shared/src/constants';
23
+import {registerExtensionsEventLogger} from './registerExtensionsEventLogger';
24
25
const LOCAL_STORAGE_SUPPORTS_PROFILING_KEY =
26
'React::DevTools::supportsProfiling';
@@ -88,9 +88,7 @@ function createPanelIfReactLoaded() {
88
89
const tabId = chrome.devtools.inspectedWindow.tabId;
90
91
- registerEventLogger((event: LogEvent) => {
92
- // TODO: hook up event logging
93
- });
91
+ registerExtensionsEventLogger();
92
93
function initBridgeAndStore() {
94
const port = chrome.runtime.connect({
packages/react-devtools-extensions/src/registerExtensionsEventLogger.js
new
+69
@@ -0,0 +1,69 @@
1
+/**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict-local
8
+ */
9
+
10
+import type {LogEvent} from 'react-devtools-shared/src/Logger';
11
+
12
+import {registerEventLogger} from 'react-devtools-shared/src/Logger';
13
+import {enableLogger} from 'react-devtools-feature-flags';
14
+
15
+let loggingIFrame = null;
16
+let missedEvents = [];
17
+function logEvent(event: LogEvent) {
18
+ if (enableLogger) {
19
+ if (loggingIFrame != null) {
20
+ loggingIFrame.contentWindow.postMessage(
21
+ {
22
+ source: 'react-devtools-logging',
23
+ event: event,
24
+ context: {
25
+ surface: 'extension',
26
+ },
27
+ },
28
+ '*',
29
+ );
30
+ } else {
31
+ missedEvents.push(event);
32
+ }
33
+ }
34
+}
35
+
36
+function handleLoggingIFrameLoaded(iframe) {
37
+ if (loggingIFrame != null) {
38
+ return;
39
+ }
40
+
41
+ loggingIFrame = iframe;
42
+ if (missedEvents.length > 0) {
43
+ missedEvents.forEach(logEvent);
44
+ missedEvents = [];
45
+ }
46
+}
47
+
48
+export function registerExtensionsEventLogger() {
49
+ // If logger is enabled, register a logger that captures logged events
50
+ // and render iframe where the logged events will be reported to
51
+ if (enableLogger) {
52
+ const loggingUrl = process.env.LOGGING_URL;
53
+ const body = document.body;
54
+ if (
55
+ typeof loggingUrl === 'string' &&
56
+ loggingUrl.length > 0 &&
57
+ body != null
58
+ ) {
59
+ registerEventLogger(logEvent);
60
+
61
+ const iframe = document.createElement('iframe');
62
+ iframe.src = loggingUrl;
63
+ iframe.onload = function(...args) {
64
+ handleLoggingIFrameLoaded(iframe);
65
+ };
66
+ body.appendChild(iframe);
67
+ }
68
+ }
69
+}
packages/react-devtools-extensions/webpack.config.js
+3
@@ -32,6 +32,8 @@ const __DEV__ = NODE_ENV === 'development';
32
33
const DEVTOOLS_VERSION = getVersionString();
34
35
+const LOGGING_URL = process.env.LOGGING_URL || null;
36
+
37
const featureFlagTarget = process.env.FEATURE_FLAG_TARGET || 'extension-oss';
38
39
const babelOptions = {
@@ -91,6 +93,7 @@ module.exports = {
93
'process.env.DEVTOOLS_PACKAGE': `"react-devtools-extensions"`,
94
'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`,
95
'process.env.GITHUB_URL': `"${GITHUB_URL}"`,
96
+ 'process.env.LOGGING_URL': `"${LOGGING_URL}"`,
97
'process.env.NODE_ENV': `"${NODE_ENV}"`,
98
'process.env.DARK_MODE_DIMMED_WARNING_COLOR': `"${DARK_MODE_DIMMED_WARNING_COLOR}"`,
99
'process.env.DARK_MODE_DIMMED_ERROR_COLOR': `"${DARK_MODE_DIMMED_ERROR_COLOR}"`,
packages/react-devtools-shared/src/Logger.js
+13
-11
@@ -10,11 +10,11 @@
10
import {enableLogger} from 'react-devtools-feature-flags';
11
12
type LoadHookNamesEvent = {|
13
- +name: 'loadHookNames',
14
- +displayName: string | null,
15
- +numberOfHooks: number | null,
16
- +durationMs: number,
17
- +resolution: 'success' | 'error' | 'timeout' | 'unknown',
13
+ +event_name: 'loadHookNames',
14
+ +event_status: 'success' | 'error' | 'timeout' | 'unknown',
15
+ +duration_ms: number,
16
+ +inspected_element_display_name: string | null,
17
+ +inspected_element_number_of_hooks: number | null,
18
|};
19
20
// prettier-ignore
@@ -23,11 +23,11 @@ export type LogEvent =
23
24
export type LogFunction = LogEvent => void;
25
26
-let loggers: Array<LogFunction> = [];
26
+let logFunctions: Array<LogFunction> = [];
27
export const logEvent: LogFunction =
28
enableLogger === true
29
? function logEvent(event: LogEvent): void {
30
- loggers.forEach(log => {
30
+ logFunctions.forEach(log => {
31
log(event);
32
});
33
}
@@ -35,13 +35,15 @@ export const logEvent: LogFunction =
35
36
export const registerEventLogger =
37
enableLogger === true
38
- ? function registerEventLogger(eventLogger: LogFunction): () => void {
38
+ ? function registerEventLogger(logFunction: LogFunction): () => void {
39
if (enableLogger) {
40
- loggers.push(eventLogger);
40
+ logFunctions.push(logFunction);
41
return function unregisterEventLogger() {
42
- loggers = loggers.filter(logger => logger !== eventLogger);
42
+ logFunctions = logFunctions.filter(log => log !== logFunction);
43
};
44
}
45
return () => {};
46
}
47
- : function registerEventLogger() {};
47
+ : function registerEventLogger(logFunction: LogFunction) {
48
+ return () => {};
49
+ };
packages/react-devtools-shared/src/hookNamesCache.js
+9
-9
@@ -99,7 +99,7 @@ export function loadHookNames(
99
100
let timeoutID;
101
let didTimeout = false;
102
- let resolution = 'unknown';
102
+ let status = 'unknown';
103
let resolvedHookNames: HookNames | null = null;
104
105
const wake = () => {
@@ -116,11 +116,11 @@ export function loadHookNames(
116
const handleLoadComplete = (durationMs: number): void => {
117
// Log duration for parsing hook names
118
logEvent({
119
- name: 'loadHookNames',
120
- displayName: element.displayName,
121
- numberOfHooks: resolvedHookNames?.size ?? null,
122
- durationMs,
123
- resolution,
119
+ event_name: 'loadHookNames',
120
+ event_status: status,
121
+ duration_ms: durationMs,
122
+ inspected_element_display_name: element.displayName,
123
+ inspected_element_number_of_hooks: resolvedHookNames?.size ?? null,
124
});
125
};
126
@@ -152,7 +152,7 @@ export function loadHookNames(
152
notFoundRecord.value = null;
153
}
154
155
- resolution = 'success';
155
+ status = 'success';
156
resolvedHookNames = hookNames;
157
done();
158
wake();
@@ -172,7 +172,7 @@ export function loadHookNames(
172
thrownRecord.status = Rejected;
173
thrownRecord.value = null;
174
175
- resolution = 'error';
175
+ status = 'error';
176
done();
177
wake();
178
},
@@ -192,7 +192,7 @@ export function loadHookNames(
192
timedoutRecord.status = Rejected;
193
timedoutRecord.value = null;
194
195
- resolution = 'timeout';
195
+ status = 'timeout';
196
done();
197
wake();
198
}, TIMEOUT);