Support logging in metro plugin

Summary: Show metro logs using the standard logs plugin

Reviewed By: passy

Differential Revision: D19697439

fbshipit-source-id: 032a9a6aa2d987945d2058e0ea494d74e5aa310e
This commit is contained in:
Michel Weststrate
2020-02-11 07:27:00 -08:00
committed by Facebook Github Bot
parent 437ec11ca7
commit dfcfca4370
3 changed files with 125 additions and 2 deletions

View File

@@ -7,10 +7,112 @@
* @format * @format
*/ */
import BaseDevice from './BaseDevice'; import BaseDevice, {LogLevel} from './BaseDevice';
import ArchivedDevice from './ArchivedDevice'; import ArchivedDevice from './ArchivedDevice';
import {v4} from 'uuid'; import {v4} from 'uuid';
// From xplat/js/metro/packages/metro/src/lib/reporting.js
export type BundleDetails = {
entryFile: string;
platform?: string;
dev: boolean;
minify: boolean;
bundleType: string;
};
// From xplat/js/metro/packages/metro/src/lib/reporting.js
export type GlobalCacheDisabledReason = 'too_many_errors' | 'too_many_misses';
/**
* A tagged union of all the actions that may happen and we may want to
* report to the tool user.
*
* Based on xplat/js/metro/packages/metro/src/lib/TerminalReporter.js
*/
type ReportableEvent =
| {
port: number;
projectRoots: ReadonlyArray<string>;
type: 'initialize_started';
}
| {type: 'initialize_done'}
| {
type: 'initialize_failed';
port: number;
error: Error;
}
| {
buildID: string;
type: 'bundle_build_done';
}
| {
buildID: string;
type: 'bundle_build_failed';
}
| {
buildID: string;
bundleDetails: BundleDetails;
type: 'bundle_build_started';
}
| {
error: Error;
type: 'bundling_error';
}
| {type: 'dep_graph_loading'}
| {type: 'dep_graph_loaded'}
| {
buildID: string;
type: 'bundle_transform_progressed';
transformedFileCount: number;
totalFileCount: number;
}
| {
type: 'global_cache_error';
error: Error;
}
| {
type: 'global_cache_disabled';
reason: GlobalCacheDisabledReason;
}
| {type: 'transform_cache_reset'}
| {
type: 'worker_stdout_chunk';
chunk: string;
}
| {
type: 'worker_stderr_chunk';
chunk: string;
}
| {
type: 'hmr_client_error';
error: Error;
}
| {
type: 'client_log';
level:
| 'trace'
| 'info'
| 'warn'
| 'log'
| 'group'
| 'groupCollapsed'
| 'groupEnd'
| 'debug';
data: Array<any>;
};
const metroLogLevelMapping: {[key: string]: LogLevel} = {
trace: 'verbose',
info: 'info',
warn: 'warn',
error: 'error',
log: 'info',
group: 'info',
groupCollapsed: 'info',
groupEnd: 'info',
debug: 'debug',
};
export default class MetroDevice extends BaseDevice { export default class MetroDevice extends BaseDevice {
ws: WebSocket; ws: WebSocket;
@@ -18,8 +120,26 @@ export default class MetroDevice extends BaseDevice {
super(serial, 'emulator', 'React Native', 'Metro'); super(serial, 'emulator', 'React Native', 'Metro');
this.ws = ws; this.ws = ws;
this.devicePlugins = []; this.devicePlugins = [];
ws.onmessage = this._handleWSMessage;
} }
_handleWSMessage = ({data}: any) => {
const message: ReportableEvent = JSON.parse(data);
if (message.type === 'client_log') {
const type: LogLevel = metroLogLevelMapping[message.level] || 'unknown';
this.addLogEntry({
date: new Date(),
pid: 0,
tid: 0,
type,
tag: message.type,
message: message.data
.map(v => (v && typeof v === 'object' ? JSON.stringify(v) : v))
.join(' '),
});
}
};
archive() { archive() {
return new ArchivedDevice( return new ArchivedDevice(
this.serial + v4(), this.serial + v4(),

View File

@@ -23,6 +23,7 @@ const METRO_DEVICE_ID = 'metro'; // there is always only one activve
async function isMetroRunning(): Promise<boolean> { async function isMetroRunning(): Promise<boolean> {
try { try {
// TODO: this prints a log error without connection, fix that
const contents = await (await global.fetch(METRO_URL)).text(); const contents = await (await global.fetch(METRO_URL)).text();
return METRO_MESSAGE.some(msg => contents.includes(msg)); return METRO_MESSAGE.some(msg => contents.includes(msg));
} catch (e) { } catch (e) {

View File

@@ -394,7 +394,9 @@ export default class LogTable extends FlipperDevicePlugin<
batchTimer: NodeJS.Timeout | undefined; batchTimer: NodeJS.Timeout | undefined;
static supportsDevice(device: Device) { static supportsDevice(device: Device) {
return device.os === 'iOS' || device.os === 'Android'; return (
device.os === 'iOS' || device.os === 'Android' || device.os === 'Metro'
);
} }
onKeyboardAction = (action: string) => { onKeyboardAction = (action: string) => {