Remove Tail
Summary: We no longer need to Tail the logs as we stream the logs over WebSockets (see D37459924 (dcbc7c40bb))
Reviewed By: lblasa
Differential Revision: D37550482
fbshipit-source-id: 92a87f2ba1ecec140bbbb9e71df107341765ad46
This commit is contained in:
committed by
Facebook GitHub Bot
parent
f8763f95fa
commit
8c2ef5738e
@@ -28,12 +28,10 @@ import {
|
|||||||
setupPrefetcher,
|
setupPrefetcher,
|
||||||
startFlipperServer,
|
startFlipperServer,
|
||||||
startServer,
|
startServer,
|
||||||
Tail,
|
|
||||||
} from 'flipper-server-core';
|
} from 'flipper-server-core';
|
||||||
import {
|
import {
|
||||||
FlipperServer,
|
FlipperServer,
|
||||||
getLogger,
|
getLogger,
|
||||||
LoggerInfo,
|
|
||||||
isTest,
|
isTest,
|
||||||
Logger,
|
Logger,
|
||||||
parseEnvironmentVariables,
|
parseEnvironmentVariables,
|
||||||
@@ -168,11 +166,6 @@ async function getFlipperServer(
|
|||||||
await server.connect();
|
await server.connect();
|
||||||
|
|
||||||
await readyForIncomingConnections(server, companionEnv);
|
await readyForIncomingConnections(server, companionEnv);
|
||||||
} else {
|
|
||||||
console.info('flipper-server: already running');
|
|
||||||
const loggerOutputFile = 'flipper-server-log.out';
|
|
||||||
|
|
||||||
tailServerLogs(path.join(staticPath, loggerOutputFile));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return getExternalServer(socketPath);
|
return getExternalServer(socketPath);
|
||||||
@@ -237,18 +230,6 @@ function getStaticDir(appPath: string) {
|
|||||||
return _staticPath;
|
return _staticPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
function tailServerLogs(logsPath: string) {
|
|
||||||
console.info('flipper-server logs located at: ', logsPath);
|
|
||||||
const tail = new Tail(logsPath);
|
|
||||||
tail.on('line', (line: any) => {
|
|
||||||
try {
|
|
||||||
const loggerInfo: LoggerInfo = JSON.parse(line);
|
|
||||||
console[loggerInfo.type](loggerInfo.msg);
|
|
||||||
} catch (_) {}
|
|
||||||
});
|
|
||||||
tail.watch();
|
|
||||||
}
|
|
||||||
|
|
||||||
// getLogger() is not yet created when the electron app starts.
|
// getLogger() is not yet created when the electron app starts.
|
||||||
// we can't create it here yet, as the real logger is wired up to
|
// we can't create it here yet, as the real logger is wired up to
|
||||||
// the redux store and the rest of the world. So we create a delegating logger
|
// the redux store and the rest of the world. So we create a delegating logger
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ export {loadSettings} from './utils/settings';
|
|||||||
export {loadLauncherSettings} from './utils/launcherSettings';
|
export {loadLauncherSettings} from './utils/launcherSettings';
|
||||||
export {loadProcessConfig} from './utils/processConfig';
|
export {loadProcessConfig} from './utils/processConfig';
|
||||||
export {getEnvironmentInfo} from './utils/environmentInfo';
|
export {getEnvironmentInfo} from './utils/environmentInfo';
|
||||||
export * from './utils/tail';
|
|
||||||
export {getGatekeepers} from './gk';
|
export {getGatekeepers} from './gk';
|
||||||
export {setupPrefetcher} from './fb-stubs/Prefetcher';
|
export {setupPrefetcher} from './fb-stubs/Prefetcher';
|
||||||
export * from './server/attachSocketServer';
|
export * from './server/attachSocketServer';
|
||||||
|
|||||||
@@ -1,144 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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 EventEmitter from 'events';
|
|
||||||
import fs, {FSWatcher} from 'fs-extra';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
export type TailOptions = {
|
|
||||||
separator: RegExp;
|
|
||||||
encoding: BufferEncoding;
|
|
||||||
fromBeginning: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
type TailBlock = {
|
|
||||||
start: number;
|
|
||||||
end: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class Tail extends EventEmitter {
|
|
||||||
absPath: string;
|
|
||||||
dispatcher = new EventEmitter();
|
|
||||||
buffer = '';
|
|
||||||
queue: TailBlock[] = [];
|
|
||||||
isWatching = false;
|
|
||||||
currentCursorPosition = 0;
|
|
||||||
watcher: FSWatcher | undefined = undefined;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private readonly filename: string,
|
|
||||||
private readonly options: TailOptions = {
|
|
||||||
separator: /[\r]{0,1}\n/,
|
|
||||||
fromBeginning: true,
|
|
||||||
encoding: 'utf8',
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.absPath = path.dirname(this.filename);
|
|
||||||
this.dispatcher.on('next', () => {
|
|
||||||
this.read_();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async watch() {
|
|
||||||
if (this.isWatching) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.isWatching = true;
|
|
||||||
|
|
||||||
let startingCursor = 0;
|
|
||||||
if (!this.options.fromBeginning) {
|
|
||||||
startingCursor = await this.latestPosition_();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.watch_(startingCursor, this.options.fromBeginning);
|
|
||||||
}
|
|
||||||
|
|
||||||
unwatch() {
|
|
||||||
if (this.watcher) {
|
|
||||||
this.watcher.close();
|
|
||||||
}
|
|
||||||
this.isWatching = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async latestPosition_(): Promise<number> {
|
|
||||||
return (await fs.stat(this.filename)).size;
|
|
||||||
}
|
|
||||||
|
|
||||||
private read_() {
|
|
||||||
if (this.queue.length >= 1) {
|
|
||||||
const block = this.queue[0];
|
|
||||||
if (block.end > block.start) {
|
|
||||||
const stream = fs.createReadStream(this.filename, {
|
|
||||||
start: block.start,
|
|
||||||
end: block.end - 1,
|
|
||||||
encoding: this.options.encoding,
|
|
||||||
});
|
|
||||||
stream.on('error', (error) => {
|
|
||||||
this.emit('error', error);
|
|
||||||
});
|
|
||||||
stream.on('end', () => {
|
|
||||||
this.queue.shift();
|
|
||||||
if (this.queue.length > 0) {
|
|
||||||
this.dispatcher.emit('next');
|
|
||||||
}
|
|
||||||
if (this.buffer.length > 0) {
|
|
||||||
this.emit('line', this.buffer);
|
|
||||||
this.buffer = '';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
stream.on('data', (d) => {
|
|
||||||
this.buffer += d;
|
|
||||||
const parts = this.buffer.split(this.options.separator);
|
|
||||||
// The last part may be an incomplete chunk, so
|
|
||||||
// push that back into the buffer. Otherwise, reset buffer.
|
|
||||||
this.buffer = parts.pop() || '';
|
|
||||||
for (const chunk of parts) {
|
|
||||||
this.emit('line', chunk);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async fileUpdated_() {
|
|
||||||
const latestPosition = await this.latestPosition_();
|
|
||||||
// Case where text is not appended but it's actually a w+
|
|
||||||
if (latestPosition < this.currentCursorPosition) {
|
|
||||||
this.currentCursorPosition = latestPosition;
|
|
||||||
} else if (latestPosition > this.currentCursorPosition) {
|
|
||||||
this.queue.push({start: this.currentCursorPosition, end: latestPosition});
|
|
||||||
this.currentCursorPosition = latestPosition;
|
|
||||||
// Only emit if the queue was empty and now is not.
|
|
||||||
if (this.queue.length == 1) {
|
|
||||||
this.dispatcher.emit('next');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private watch_(cursor: number, readPrevious: boolean) {
|
|
||||||
this.currentCursorPosition = cursor;
|
|
||||||
if (readPrevious) {
|
|
||||||
this.fileUpdated_();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.watcher = fs.watch(this.filename, {}, (eventType, filename) => {
|
|
||||||
this.watchEvent_(eventType, filename);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private watchEvent_(eventType: string, _filename: string) {
|
|
||||||
try {
|
|
||||||
if (eventType === 'change') {
|
|
||||||
this.fileUpdated_();
|
|
||||||
}
|
|
||||||
} catch (err) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user