From a9b17ac63711213653c559c0f47c000e2b7bc656 Mon Sep 17 00:00:00 2001 From: Luke De Feo Date: Tue, 4 Apr 2023 07:58:57 -0700 Subject: [PATCH] Add log tailing infra and downgrade resize observer error to warn Summary: Resize oberserver limit exceeded appears to be a benign error that we can safely ignore, added ability to change log level. Given we report errors to our user logs, fb log view and console the console log patching has been centralised and now logs are pushed to whatever destinations we have. Reviewed By: lblasa Differential Revision: D44666836 fbshipit-source-id: e028dbc52b00947097833f9f3619189226247e1d --- .../src/chrome/ConsoleLogs.tsx | 47 ++++++++------ .../flipper-ui-core/src/consoleLogTailer.tsx | 63 +++++++++++++++++++ .../src/startFlipperDesktop.tsx | 2 + 3 files changed, 92 insertions(+), 20 deletions(-) create mode 100644 desktop/flipper-ui-core/src/consoleLogTailer.tsx diff --git a/desktop/flipper-ui-core/src/chrome/ConsoleLogs.tsx b/desktop/flipper-ui-core/src/chrome/ConsoleLogs.tsx index d3f9814a8..b1f345c16 100644 --- a/desktop/flipper-ui-core/src/chrome/ConsoleLogs.tsx +++ b/desktop/flipper-ui-core/src/chrome/ConsoleLogs.tsx @@ -9,7 +9,7 @@ import {useMemo} from 'react'; import React from 'react'; -import {Console, Hook} from 'console-feed'; +import {Console} from 'console-feed'; import type {Methods} from 'console-feed/lib/definitions/Methods'; import type {Styles} from 'console-feed/lib/definitions/Styles'; import {createState, useValue} from 'flipper-plugin'; @@ -20,33 +20,40 @@ import {Button, Dropdown, Menu, Checkbox} from 'antd'; import {DownOutlined} from '@ant-design/icons'; import {DeleteOutlined} from '@ant-design/icons'; import CBuffer from 'cbuffer'; +import {addLogTailer} from '../consoleLogTailer'; +import {v4} from 'uuid'; const MAX_DISPLAY_LOG_ITEMS = 1000; const MAX_EXPORT_LOG_ITEMS = 5000; // A list5 of log items meant to be used for exporting (and subsequent debugging) only -export const exportLogs = new CBuffer(MAX_EXPORT_LOG_ITEMS); -export const displayLogsAtom = createState([]); +export const exportLogs = new CBuffer( + MAX_EXPORT_LOG_ITEMS, +); +export const displayLogsAtom = createState([]); export const errorCounterAtom = createState(0); -export function enableConsoleHook() { - Hook( - window.console, - (log) => { - exportLogs.push(log); +type ConsoleFeedLogMessage = { + id: string; + method: Methods; + data: any[]; +}; - if (log.method === 'debug') { - return; // See below, skip debug messages which are generated very aggressively by Flipper - } - const newLogs = displayLogsAtom.get().slice(-MAX_DISPLAY_LOG_ITEMS); - newLogs.push(log); - displayLogsAtom.set(newLogs); - if (log.method === 'error' || log.method === 'assert') { - errorCounterAtom.set(errorCounterAtom.get() + 1); - } - }, - false, - ); +export function enableConsoleHook() { + addLogTailer((level, ...data) => { + const logMessage = {method: level, data: data, id: v4()}; + exportLogs.push(logMessage); + + if (level === 'debug') { + return; // See below, skip debug messages which are generated very aggressively by Flipper + } + const newLogs = displayLogsAtom.get().slice(-MAX_DISPLAY_LOG_ITEMS); + newLogs.push(logMessage); + displayLogsAtom.set(newLogs); + if (level === 'error') { + errorCounterAtom.set(errorCounterAtom.get() + 1); + } + }); } function clearLogs() { diff --git a/desktop/flipper-ui-core/src/consoleLogTailer.tsx b/desktop/flipper-ui-core/src/consoleLogTailer.tsx new file mode 100644 index 000000000..aff41ecb4 --- /dev/null +++ b/desktop/flipper-ui-core/src/consoleLogTailer.tsx @@ -0,0 +1,63 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import {getStringFromErrorLike, LoggerTypes} from 'flipper-common'; + +const logLevels: LoggerTypes[] = ['debug', 'info', 'warn', 'error']; + +export type LogTailer = (level: LoggerTypes, ...data: Array) => void; + +const logTailers: LogTailer[] = []; + +export function addLogTailer(handler: LogTailer) { + logTailers.push(handler); +} + +export function initLogTailer() { + const originalConsole: {[key: string]: any} = console; + //store the raw console log functions here + const originalConsoleLogFunctions: {[key: string]: (...args: any) => void} = + {} as { + [key: string]: (...args: any) => void; + }; + // React Devtools also patches the console methods: + // https://github.com/facebook/react/blob/206d61f72214e8ae5b935f0bf8628491cb7f0797/packages/react-devtools-shared/src/backend/console.js#L141 + // Not using a proxy object here because it isn't compatible with their patching process. + // Instead replace the methods on the console itself. + // Doesn't matter who patches first, single thread means it will be consistent. + for (const level of logLevels) { + const originalConsoleLogFunction = originalConsole[level]; + originalConsoleLogFunctions[level] = originalConsoleLogFunction; + const overrideMethod = (...args: Array) => { + const message = getStringFromErrorLike(args); + const newLevel = transformLogLevel(level, message); + + const newConsoleLogFunction = originalConsoleLogFunctions[newLevel]; + const result = newConsoleLogFunction(...args); + logTailers.forEach((handler) => { + handler(newLevel, ...args); + }); + return result; + }; + + overrideMethod.__FLIPPER_ORIGINAL_METHOD__ = originalConsoleLogFunction; + originalConsole[level] = overrideMethod; + } +} + +function transformLogLevel(level: LoggerTypes, message: string) { + if ( + level === 'error' && + message.includes('ResizeObserver loop limit exceeded') + ) { + return 'warn'; + } + + return level; +} diff --git a/desktop/flipper-ui-core/src/startFlipperDesktop.tsx b/desktop/flipper-ui-core/src/startFlipperDesktop.tsx index f3048503c..04b241c9b 100644 --- a/desktop/flipper-ui-core/src/startFlipperDesktop.tsx +++ b/desktop/flipper-ui-core/src/startFlipperDesktop.tsx @@ -11,6 +11,7 @@ import {Provider} from 'react-redux'; import {createRoot} from 'react-dom/client'; import {init as initLogger} from './fb-stubs/Logger'; +import {initLogTailer} from './consoleLogTailer'; import {SandyApp} from './sandy-chrome/SandyApp'; import {Persistor, persistStore} from 'redux-persist'; import dispatcher from './dispatcher/index'; @@ -139,6 +140,7 @@ class AppFrame extends React.Component< function init(flipperServer: FlipperServer) { const settings = getRenderHostInstance().serverConfig.settings; const store = getStore(); + initLogTailer(); const logger = initLogger(store); setLoggerInstance(logger);