213 lines
6.0 KiB
JavaScript
213 lines
6.0 KiB
JavaScript
/**
|
|
* 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
|
|
* @format
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
import Platform from '../Utilities/Platform';
|
|
import RCTLog from '../Utilities/RCTLog';
|
|
import * as LogBoxData from './Data/LogBoxData';
|
|
import {parseLogBoxLog, parseInterpolation} from './Data/parseLogBoxLog';
|
|
|
|
import type {IgnorePattern} from './Data/LogBoxData';
|
|
|
|
let LogBox;
|
|
|
|
/**
|
|
* LogBox displays logs in the app.
|
|
*/
|
|
if (__DEV__) {
|
|
// LogBox needs to insert itself early,
|
|
// in order to access the component stacks appended by React DevTools.
|
|
const {error, warn} = console;
|
|
let errorImpl = error.bind(console);
|
|
let warnImpl = warn.bind(console);
|
|
|
|
(console: any).error = function(...args) {
|
|
errorImpl(...args);
|
|
};
|
|
(console: any).warn = function(...args) {
|
|
warnImpl(...args);
|
|
};
|
|
|
|
LogBox = {
|
|
ignoreLogs: (patterns: $ReadOnlyArray<IgnorePattern>): void => {
|
|
LogBoxData.addIgnorePatterns(patterns);
|
|
},
|
|
|
|
ignoreAllLogs: (value?: ?boolean): void => {
|
|
LogBoxData.setDisabled(value == null ? true : value);
|
|
},
|
|
|
|
uninstall: (): void => {
|
|
errorImpl = error;
|
|
warnImpl = warn;
|
|
delete (console: any).disableLogBox;
|
|
},
|
|
|
|
install: (): void => {
|
|
// Trigger lazy initialization of module.
|
|
require('../NativeModules/specs/NativeLogBox');
|
|
|
|
errorImpl = function(...args) {
|
|
registerError(...args);
|
|
};
|
|
|
|
warnImpl = function(...args) {
|
|
registerWarning(...args);
|
|
};
|
|
|
|
if ((console: any).disableYellowBox === true) {
|
|
LogBoxData.setDisabled(true);
|
|
console.warn(
|
|
'console.disableYellowBox has been deprecated and will be removed in a future release. Please use LogBox.ignoreAllLogs(value) instead.',
|
|
);
|
|
}
|
|
|
|
(Object.defineProperty: any)(console, 'disableYellowBox', {
|
|
configurable: true,
|
|
get: () => LogBoxData.isDisabled(),
|
|
set: value => {
|
|
LogBoxData.setDisabled(value);
|
|
console.warn(
|
|
'console.disableYellowBox has been deprecated and will be removed in a future release. Please use LogBox.ignoreAllLogs(value) instead.',
|
|
);
|
|
},
|
|
});
|
|
|
|
if (Platform.isTesting) {
|
|
LogBoxData.setDisabled(true);
|
|
}
|
|
|
|
RCTLog.setWarningHandler((...args) => {
|
|
registerWarning(...args);
|
|
});
|
|
},
|
|
};
|
|
|
|
const isRCTLogAdviceWarning = (...args) => {
|
|
// RCTLogAdvice is a native logging function designed to show users
|
|
// a message in the console, but not show it to them in Logbox.
|
|
return typeof args[0] === 'string' && args[0].startsWith('(ADVICE)');
|
|
};
|
|
|
|
const isWarningModuleWarning = (...args) => {
|
|
return typeof args[0] === 'string' && args[0].startsWith('Warning: ');
|
|
};
|
|
|
|
const registerWarning = (...args): void => {
|
|
// Let warnings within LogBox itself fall through.
|
|
if (LogBoxData.isLogBoxErrorMessage(String(args[0]))) {
|
|
error.call(console, ...args);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
if (!isRCTLogAdviceWarning(...args)) {
|
|
const {category, message, componentStack} = parseLogBoxLog(args);
|
|
|
|
if (!LogBoxData.isMessageIgnored(message.content)) {
|
|
// Be sure to pass LogBox warnings through.
|
|
warn.call(console, ...args);
|
|
|
|
LogBoxData.addLog({
|
|
level: 'warn',
|
|
category,
|
|
message,
|
|
componentStack,
|
|
});
|
|
}
|
|
}
|
|
} catch (err) {
|
|
LogBoxData.reportLogBoxError(err);
|
|
}
|
|
};
|
|
|
|
const registerError = (...args): void => {
|
|
// Let errors within LogBox itself fall through.
|
|
if (LogBoxData.isLogBoxErrorMessage(args[0])) {
|
|
error.call(console, ...args);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
if (!isWarningModuleWarning(...args)) {
|
|
// Only show LogBox for the 'warning' module, otherwise pass through.
|
|
// By passing through, this will get picked up by the React console override,
|
|
// potentially adding the component stack. React then passes it back to the
|
|
// React Native ExceptionsManager, which reports it to LogBox as an error.
|
|
//
|
|
// The 'warning' module needs to be handled here because React internally calls
|
|
// `console.error('Warning: ')` with the component stack already included.
|
|
error.call(console, ...args);
|
|
return;
|
|
}
|
|
|
|
const format = args[0].replace('Warning: ', '');
|
|
const filterResult = LogBoxData.checkWarningFilter(format);
|
|
if (filterResult.suppressCompletely) {
|
|
return;
|
|
}
|
|
|
|
let level = 'error';
|
|
if (filterResult.suppressDialog_LEGACY === true) {
|
|
level = 'warn';
|
|
} else if (filterResult.forceDialogImmediately === true) {
|
|
level = 'fatal'; // Do not downgrade. These are real bugs with same severity as throws.
|
|
}
|
|
|
|
// Unfortunately, we need to add the Warning: prefix back for downstream dependencies.
|
|
args[0] = `Warning: ${filterResult.finalFormat}`;
|
|
const {category, message, componentStack} = parseLogBoxLog(args);
|
|
|
|
if (!LogBoxData.isMessageIgnored(message.content)) {
|
|
// Interpolate the message so they are formatted for adb and other CLIs.
|
|
// This is different than the message.content above because it includes component stacks.
|
|
const interpolated = parseInterpolation(args);
|
|
error.call(console, interpolated.message.content);
|
|
|
|
LogBoxData.addLog({
|
|
level,
|
|
category,
|
|
message,
|
|
componentStack,
|
|
});
|
|
}
|
|
} catch (err) {
|
|
LogBoxData.reportLogBoxError(err);
|
|
}
|
|
};
|
|
} else {
|
|
LogBox = {
|
|
ignoreLogs: (patterns: $ReadOnlyArray<IgnorePattern>): void => {
|
|
// Do nothing.
|
|
},
|
|
|
|
ignoreAllLogs: (value?: ?boolean): void => {
|
|
// Do nothing.
|
|
},
|
|
|
|
install: (): void => {
|
|
// Do nothing.
|
|
},
|
|
|
|
uninstall: (): void => {
|
|
// Do nothing.
|
|
},
|
|
};
|
|
}
|
|
|
|
module.exports = (LogBox: {
|
|
ignoreLogs($ReadOnlyArray<IgnorePattern>): void,
|
|
ignoreAllLogs(?boolean): void,
|
|
install(): void,
|
|
uninstall(): void,
|
|
...
|
|
});
|