@samitouri / QOS-React-2 / commits / 75b9869648

[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);