Skip to content

Commit

Permalink
exthost: use marker to avoid duplicating written log messages
Browse files Browse the repository at this point in the history
Fixes #104686
  • Loading branch information
connor4312 committed Dec 9, 2020
1 parent 7491d39 commit 633521c
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 10 deletions.
12 changes: 8 additions & 4 deletions src/bootstrap-fork.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,11 @@ function pipeLoggingToParent() {
const original = console[method];
console[method] = function () {
safeSendConsoleMessage(severity, safeToArray(arguments));

const stream = method === 'error' || method === 'warn' ? process.stderr : process.stdout;
stream.write('\nSTART_NATIVE_LOG\n');
original.apply(console, arguments);
stream.write('\nEND_NATIVE_LOG\n');
};
} else {
console[method] = function () { safeSendConsoleMessage(severity, safeToArray(arguments)); };
Expand All @@ -162,16 +166,16 @@ function pipeLoggingToParent() {

// Pass console logging to the outside so that we have it in the main side if told so
if (process.env.VERBOSE_LOGGING === 'true') {
wrapConsoleMethod('info', 'log');
wrapConsoleMethod('log', 'log');
wrapConsoleMethod('warn', 'log');
wrapConsoleMethod('error', 'warn');
wrapConsoleMethod('warn', 'warn');
wrapConsoleMethod('error', 'error');
} else if (process.env.VSCODE_LOG_NATIVE !== 'true') {
console.log = function () { /* ignore */ };
console.warn = function () { /* ignore */ };
console.info = function () { /* ignore */ };
wrapConsoleMethod('error', 'error');
}

wrapConsoleMethod('error', 'error');
}

function handleExceptions() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { IOutputChannelRegistry, Extensions } from 'vs/workbench/services/output/common/output';
import { isUUID } from 'vs/base/common/uuid';
import { join } from 'vs/base/common/path';
import { Readable, Writable } from 'stream';
import { StringDecoder } from 'string_decoder';

export interface ILocalProcessExtensionHostInitData {
readonly autoStart: boolean;
Expand All @@ -55,6 +57,11 @@ export interface ILocalProcessExtensionHostDataProvider {
getInitData(): Promise<ILocalProcessExtensionHostInitData>;
}

const enum NativeLogMarkers {
Start = 'START_NATIVE_LOG',
End = 'END_NATIVE_LOG',
}

export class LocalProcessExtensionHost implements IExtensionHost {

public readonly kind = ExtensionHostKind.LocalProcess;
Expand Down Expand Up @@ -224,13 +231,11 @@ export class LocalProcessExtensionHost implements IExtensionHost {

// Catch all output coming from the extension host process
type Output = { data: string, format: string[] };
this._extensionHostProcess.stdout!.setEncoding('utf8');
this._extensionHostProcess.stderr!.setEncoding('utf8');
const onStdout = Event.fromNodeEventEmitter<string>(this._extensionHostProcess.stdout!, 'data');
const onStderr = Event.fromNodeEventEmitter<string>(this._extensionHostProcess.stderr!, 'data');
const onStdout = this._handleProcessOutputStream(this._extensionHostProcess.stdout!);
const onStderr = this._handleProcessOutputStream(this._extensionHostProcess.stderr!);
const onOutput = Event.any(
Event.map(onStdout, o => ({ data: `%c${o}`, format: [''] })),
Event.map(onStderr, o => ({ data: `%c${o}`, format: ['color: red'] }))
Event.map(onStdout.event, o => ({ data: `%c${o}`, format: [''] })),
Event.map(onStderr.event, o => ({ data: `%c${o}`, format: ['color: red'] }))
);

// Debounce all output, so we can render it in the Chrome console as a group
Expand Down Expand Up @@ -519,6 +524,44 @@ export class LocalProcessExtensionHost implements IExtensionHost {
this._onExit.fire([code, signal]);
}

private _handleProcessOutputStream(stream: Readable) {
let last = '';
let isOmitting = false;
const event = new Emitter<string>();
const decoder = new StringDecoder('utf-8');
stream.pipe(new Writable({
write(chunk, _encoding, callback) {
// not a fancy approach, but this is the same approach used by the split2
// module which is well-optimized (https:/mcollina/split2)
last += typeof chunk === 'string' ? chunk : decoder.write(chunk);
let lines = last.split(/\r?\n/g);
last = lines.pop()!;

// protected against an extension spamming and leaking memory if no new line is written.
if (last.length > 10_000) {
lines = [last];
last = '';
}

for (const line of lines) {
if (isOmitting) {
if (line === NativeLogMarkers.End) {
isOmitting = false;
}
} else if (line === NativeLogMarkers.Start) {
isOmitting = true;
} else if (line.length) {
event.fire(line + '\n');
}
}

callback();
}
}));

return event;
}

public async enableInspectPort(): Promise<boolean> {
if (typeof this._inspectPort === 'number') {
return true;
Expand Down

0 comments on commit 633521c

Please sign in to comment.