Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DevTools] Extension reports logged events when feature flag is enabled #22475

Merged
merged 3 commits into from Sep 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 2 additions & 4 deletions packages/react-devtools-extensions/src/main.js
Expand Up @@ -18,9 +18,9 @@ import {
localStorageRemoveItem,
localStorageSetItem,
} from 'react-devtools-shared/src/storage';
import {registerEventLogger} from 'react-devtools-shared/src/Logger';
import DevTools from 'react-devtools-shared/src/devtools/views/DevTools';
import {__DEBUG__} from 'react-devtools-shared/src/constants';
import {registerExtensionsEventLogger} from './registerExtensionsEventLogger';

const LOCAL_STORAGE_SUPPORTS_PROFILING_KEY =
'React::DevTools::supportsProfiling';
Expand Down Expand Up @@ -88,9 +88,7 @@ function createPanelIfReactLoaded() {

const tabId = chrome.devtools.inspectedWindow.tabId;

registerEventLogger((event: LogEvent) => {
// TODO: hook up event logging
});
registerExtensionsEventLogger();

function initBridgeAndStore() {
const port = chrome.runtime.connect({
Expand Down
@@ -0,0 +1,69 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
*/

import type {LogEvent} from 'react-devtools-shared/src/Logger';

import {registerEventLogger} from 'react-devtools-shared/src/Logger';
import {enableLogger} from 'react-devtools-feature-flags';

let loggingIFrame = null;
let missedEvents = [];
function logEvent(event: LogEvent) {
if (enableLogger) {
if (loggingIFrame != null) {
loggingIFrame.contentWindow.postMessage(
{
source: 'react-devtools-logging',
event: event,
context: {
surface: 'extension',
},
},
'*',
);
} else {
missedEvents.push(event);
}
}
}

function handleLoggingIFrameLoaded(iframe) {
if (loggingIFrame != null) {
return;
}

loggingIFrame = iframe;
if (missedEvents.length > 0) {
missedEvents.forEach(logEvent);
missedEvents = [];
}
}

export function registerExtensionsEventLogger() {
// If logger is enabled, register a logger that captures logged events
// and render iframe where the logged events will be reported to
if (enableLogger) {
const loggingUrl = process.env.LOGGING_URL;
const body = document.body;
if (
typeof loggingUrl === 'string' &&
loggingUrl.length > 0 &&
body != null
) {
registerEventLogger(logEvent);

const iframe = document.createElement('iframe');
iframe.src = loggingUrl;
iframe.onload = function(...args) {
handleLoggingIFrameLoaded(iframe);
};
body.appendChild(iframe);
}
}
}
3 changes: 3 additions & 0 deletions packages/react-devtools-extensions/webpack.config.js
Expand Up @@ -32,6 +32,8 @@ const __DEV__ = NODE_ENV === 'development';

const DEVTOOLS_VERSION = getVersionString();

const LOGGING_URL = process.env.LOGGING_URL || null;

const featureFlagTarget = process.env.FEATURE_FLAG_TARGET || 'extension-oss';

const babelOptions = {
Expand Down Expand Up @@ -91,6 +93,7 @@ module.exports = {
'process.env.DEVTOOLS_PACKAGE': `"react-devtools-extensions"`,
'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`,
'process.env.GITHUB_URL': `"${GITHUB_URL}"`,
'process.env.LOGGING_URL': `"${LOGGING_URL}"`,
'process.env.NODE_ENV': `"${NODE_ENV}"`,
'process.env.DARK_MODE_DIMMED_WARNING_COLOR': `"${DARK_MODE_DIMMED_WARNING_COLOR}"`,
'process.env.DARK_MODE_DIMMED_ERROR_COLOR': `"${DARK_MODE_DIMMED_ERROR_COLOR}"`,
Expand Down
24 changes: 13 additions & 11 deletions packages/react-devtools-shared/src/Logger.js
Expand Up @@ -10,11 +10,11 @@
import {enableLogger} from 'react-devtools-feature-flags';

type LoadHookNamesEvent = {|
+name: 'loadHookNames',
+displayName: string | null,
+numberOfHooks: number | null,
+durationMs: number,
+resolution: 'success' | 'error' | 'timeout' | 'unknown',
+event_name: 'loadHookNames',
bvaughn marked this conversation as resolved.
Show resolved Hide resolved
+event_status: 'success' | 'error' | 'timeout' | 'unknown',
+duration_ms: number,
+inspected_element_display_name: string | null,
+inspected_element_number_of_hooks: number | null,
|};

// prettier-ignore
Expand All @@ -23,25 +23,27 @@ export type LogEvent =

export type LogFunction = LogEvent => void;

let loggers: Array<LogFunction> = [];
let logFunctions: Array<LogFunction> = [];
export const logEvent: LogFunction =
enableLogger === true
? function logEvent(event: LogEvent): void {
loggers.forEach(log => {
logFunctions.forEach(log => {
log(event);
});
}
: function logEvent() {};

export const registerEventLogger =
enableLogger === true
? function registerEventLogger(eventLogger: LogFunction): () => void {
? function registerEventLogger(logFunction: LogFunction): () => void {
if (enableLogger) {
loggers.push(eventLogger);
logFunctions.push(logFunction);
return function unregisterEventLogger() {
loggers = loggers.filter(logger => logger !== eventLogger);
logFunctions = logFunctions.filter(log => log !== logFunction);
};
}
return () => {};
}
: function registerEventLogger() {};
: function registerEventLogger(logFunction: LogFunction) {
return () => {};
};
18 changes: 9 additions & 9 deletions packages/react-devtools-shared/src/hookNamesCache.js
Expand Up @@ -99,7 +99,7 @@ export function loadHookNames(

let timeoutID;
let didTimeout = false;
let resolution = 'unknown';
let status = 'unknown';
let resolvedHookNames: HookNames | null = null;

const wake = () => {
Expand All @@ -116,11 +116,11 @@ export function loadHookNames(
const handleLoadComplete = (durationMs: number): void => {
// Log duration for parsing hook names
logEvent({
name: 'loadHookNames',
displayName: element.displayName,
numberOfHooks: resolvedHookNames?.size ?? null,
durationMs,
resolution,
event_name: 'loadHookNames',
event_status: status,
duration_ms: durationMs,
inspected_element_display_name: element.displayName,
inspected_element_number_of_hooks: resolvedHookNames?.size ?? null,
});
};

Expand Down Expand Up @@ -152,7 +152,7 @@ export function loadHookNames(
notFoundRecord.value = null;
}

resolution = 'success';
status = 'success';
resolvedHookNames = hookNames;
done();
wake();
Expand All @@ -172,7 +172,7 @@ export function loadHookNames(
thrownRecord.status = Rejected;
thrownRecord.value = null;

resolution = 'error';
status = 'error';
done();
wake();
},
Expand All @@ -192,7 +192,7 @@ export function loadHookNames(
timedoutRecord.status = Rejected;
timedoutRecord.value = null;

resolution = 'timeout';
status = 'timeout';
done();
wake();
}, TIMEOUT);
Expand Down