From 833ea9f5d801fb6fa006a7c9c99ac56dd5241222 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Fri, 26 Aug 2016 09:43:31 -0700 Subject: [PATCH 1/2] Improve OmniSharp server logging --- gulpfile.js | 8 ++++-- src/omnisharp/download.ts | 27 +++++++++--------- src/omnisharp/launcher.ts | 10 +++++-- src/omnisharp/logger.ts | 59 +++++++++++++++++++++++++++++++++++++++ src/omnisharp/server.ts | 36 +++++++++++++++++++----- 5 files changed, 115 insertions(+), 25 deletions(-) create mode 100644 src/omnisharp/logger.ts diff --git a/gulpfile.js b/gulpfile.js index 2ff76ad..f7eb74b 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -17,6 +17,7 @@ const debugInstall = require('./out/coreclr-debug/install.js'); const fs_extra = require('fs-extra-promise'); const omnisharp = require('./out/omnisharp/omnisharp'); const download = require('./out/omnisharp/download'); +const logger = require('./out/omnisharp/logger'); const platform = require('./out/platform'); const child_process = require('child_process'); @@ -35,8 +36,11 @@ gulp.task('clean', ['omnisharp:clean', 'debugger:clean', 'package:clean'], () = /// Omnisharp Tasks function installOmnisharp(omnisharps) { - const logger = (message) => { console.log(message); }; - const promises = omnisharps.map((omni) => download.go(omni.flavor, omni.platform, logger)); + const promises = omnisharps.map((omni, index) => { + const log = new logger.Logger(message => process.stdout.write(message), index.toString()); + + return download.go(omni.flavor, omni.platform, log); + }); return Promise.all(promises); } diff --git a/src/omnisharp/download.ts b/src/omnisharp/download.ts index 8b44f58..a671ea3 100644 --- a/src/omnisharp/download.ts +++ b/src/omnisharp/download.ts @@ -19,6 +19,7 @@ import {parse} from 'url'; import {Flavor, getInstallDirectory} from './omnisharp'; import {Platform} from '../platform'; import {getProxyAgent} from '../proxy'; +import {Logger} from './logger'; const decompress = require('decompress'); @@ -108,20 +109,17 @@ function download(urlString: string, proxy?: string, strictSSL?: boolean): Promi }); } -export function go(flavor: Flavor, platform: Platform, log?: (message: string) => void, proxy?: string, strictSSL?: boolean) { +export function go(flavor: Flavor, platform: Platform, logger: Logger, proxy?: string, strictSSL?: boolean) { return new Promise((resolve, reject) => { - log = log || (_ => { }); - - log(`Flavor: ${flavor}, Platform: ${platform}`); - const fileName = getDownloadFileName(flavor, platform); const installDirectory = getInstallDirectory(flavor); - log(`[INFO] Installing OmniSharp to ${installDirectory}`); + logger.appendLine(`Installing OmniSharp to ${installDirectory}`); + logger.increaseIndent(); const urlString = `${BaseDownloadUrl}/${fileName}`; - log(`[INFO] Attempting to download ${urlString}`); + logger.appendLine(`Attempting to download ${fileName}`); return download(urlString, proxy, strictSSL) .then(inStream => { @@ -130,7 +128,7 @@ export function go(flavor: Flavor, platform: Platform, log?: (message: string) = return reject(err); } - log(`[INFO] Downloading to ${tmpPath}...`); + logger.appendLine(`Downloading to ${tmpPath}...`); const outStream = fs.createWriteStream(null, { fd: fd }); @@ -140,16 +138,16 @@ export function go(flavor: Flavor, platform: Platform, log?: (message: string) = outStream.once('finish', () => { // At this point, the asset has finished downloading. - log(`[INFO] Download complete!`); - log(`[INFO] Decompressing...`); + logger.appendLine(`Download complete!`); + logger.appendLine(`Decompressing...`); return decompress(tmpPath, installDirectory) .then(files => { - log(`[INFO] Done! ${files.length} files unpacked.`); + logger.appendLine(`Done! ${files.length} files unpacked.\n`); return resolve(true); }) .catch(err => { - log(`[ERROR] ${err}`); + logger.appendLine(`[ERROR] ${err}`); return reject(err); }); }); @@ -159,7 +157,10 @@ export function go(flavor: Flavor, platform: Platform, log?: (message: string) = }) .catch(err => { - log(`[ERROR] ${err}`); + logger.appendLine(`[ERROR] ${err}`); }); + }).then(res => { + logger.decreaseIndent(); + return res; }); } \ No newline at end of file diff --git a/src/omnisharp/launcher.ts b/src/omnisharp/launcher.ts index dd95a3f..6348163 100644 --- a/src/omnisharp/launcher.ts +++ b/src/omnisharp/launcher.ts @@ -149,6 +149,7 @@ export interface LaunchDetails { export interface LaunchResult { process: ChildProcess; command: string; + usingMono: boolean; } export function launchOmniSharp(details: LaunchDetails): Promise { @@ -205,7 +206,8 @@ function launchWindows(details: LaunchDetails): Promise { return resolve({ process, - command: details.serverPath + command: details.serverPath, + usingMono: false }); }); } @@ -231,7 +233,8 @@ function launchNixCoreCLR(details: LaunchDetails): Promise { return resolve({ process, - command: details.serverPath + command: details.serverPath, + usingMono: false }); }); } @@ -249,7 +252,8 @@ function launchNixMono(details: LaunchDetails): Promise { return resolve({ process, - command: details.serverPath + command: details.serverPath, + usingMono: true }); }); }); diff --git a/src/omnisharp/logger.ts b/src/omnisharp/logger.ts new file mode 100644 index 0000000..6f38da3 --- /dev/null +++ b/src/omnisharp/logger.ts @@ -0,0 +1,59 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +export class Logger { + private _writer: (message: string) => void; + private _prefix: string; + + private _indent: string = ' '; + private _indentLevel: number = 0; + private _atLineStart: boolean = false; + + constructor(writer: (message: string) => void, prefix?: string) { + this._writer = writer; + this._prefix = prefix; + } + + private _appendCore(message: string): void { + if (this._atLineStart) { + if (this._indentLevel > 0) { + const repeatCount = this._indentLevel; + const indent = this._indent.repeat(repeatCount); + this._writer(indent); + } + + if (this._prefix) { + this._writer(`[${this._prefix}] `); + } + + this._atLineStart = false; + } + + this._writer(message); + } + + public increaseIndent(): void { + this._indentLevel += 1; + } + + public decreaseIndent(): void { + if (this._indentLevel > 0) { + this._indentLevel -= 1; + } + } + + public append(message?: string): void { + message = message || ""; + this._appendCore(message); + } + + public appendLine(message?: string): void { + message = message || ""; + this._appendCore(message + '\n'); + this._atLineStart = true; + } +} \ No newline at end of file diff --git a/src/omnisharp/server.ts b/src/omnisharp/server.ts index 5ec61bc..885dcc3 100644 --- a/src/omnisharp/server.ts +++ b/src/omnisharp/server.ts @@ -13,6 +13,7 @@ import {launchOmniSharp} from './launcher'; import * as protocol from './protocol'; import * as omnisharp from './omnisharp'; import * as download from './download'; +import {Logger} from './logger'; import {DelayTracker} from './delayTracker'; import {LaunchTarget, findLaunchTargets, getDefaultFlavor} from './launcher'; import {Platform, getCurrentPlatform} from '../platform'; @@ -76,6 +77,7 @@ export abstract class OmnisharpServer { private _queue: Request[] = []; private _isProcessingQueue = false; private _channel: vscode.OutputChannel; + protected _logger: Logger; private _isDebugEnable: boolean = false; @@ -84,8 +86,10 @@ export abstract class OmnisharpServer { constructor(reporter: TelemetryReporter) { this._extraArgs = []; - this._channel = vscode.window.createOutputChannel('OmniSharp Log'); this._reporter = reporter; + + this._channel = vscode.window.createOutputChannel('OmniSharp Log'); + this._logger = new Logger(message => this._channel.append(message)); } public isRunning(): boolean { @@ -276,15 +280,33 @@ export abstract class OmnisharpServer { args = args.concat(this._extraArgs); - this._fireEvent(Events.StdOut, `[INFO] Starting OmniSharp at '${solutionPath}'...\n`); + this._logger.appendLine(`Starting OmniSharp server at ${new Date().toLocaleString()}`); + this._logger.increaseIndent(); + this._logger.appendLine(`Target: ${solutionPath}`); + this._logger.decreaseIndent(); + this._logger.appendLine(); + this._fireEvent(Events.BeforeServerStart, solutionPath); return launchOmniSharp({serverPath, flavor, cwd, args}).then(value => { + if (value.usingMono) { + this._logger.appendLine(`OmniSharp server started wth Mono`); + } + else { + this._logger.appendLine(`OmniSharp server started`); + } + + this._logger.increaseIndent(); + this._logger.appendLine(`Path: ${value.command}`); + this._logger.appendLine(`PID: ${value.process.pid}`); + this._logger.decreaseIndent(); + this._logger.appendLine(); + this._serverProcess = value.process; this._delayTrackers = {}; - this._fireEvent(Events.StdOut, `[INFO] Started OmniSharp from '${value.command}' with process id ${value.process.pid}...\n`); this._setState(ServerState.Started); this._fireEvent(Events.ServerStart, solutionPath); + return this._doConnect(); }).then(() => { return vscode.commands.getCommands() @@ -440,11 +462,11 @@ export abstract class OmnisharpServer { const config = vscode.workspace.getConfiguration(); const proxy = config.get('http.proxy'); const strictSSL = config.get('http.proxyStrictSSL', true); - const logger = (message: string) => { this._channel.appendLine(message); }; + const logger = (message: string) => { this._logger.appendLine(message); }; this._fireEvent(Events.BeforeServerInstall, this); - return download.go(flavor, platform, logger, proxy, strictSSL).then(_ => { + return download.go(flavor, platform, this._logger, proxy, strictSSL).then(_ => { return omnisharp.findServerPath(installDirectory); }); }); @@ -622,7 +644,7 @@ export class StdioOmnisharpServer extends OmnisharpServer { const onLineReceived = (line: string) => { if (line[0] !== '{') { - this._fireEvent(Events.StdOut, `${line}\n`); + this._logger.appendLine(line); return; } @@ -681,7 +703,7 @@ export class StdioOmnisharpServer extends OmnisharpServer { if (packet.Event === 'log') { // handle log events const entry = <{ LogLevel: string; Name: string; Message: string; }>packet.Body; - this._fireEvent(Events.StdOut, `[${entry.LogLevel}:${entry.Name}] ${entry.Message}\n`); + this._logger.appendLine(`[${entry.LogLevel}:${entry.Name}] ${entry.Message}`); return; } else { // fwd all other events From bac456cbbb84772bb18e3000629214cc97def177 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Fri, 26 Aug 2016 10:45:35 -0700 Subject: [PATCH 2/2] Tweak indent string generation slightly to make greggm smile --- src/omnisharp/logger.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/omnisharp/logger.ts b/src/omnisharp/logger.ts index 6f38da3..ccb89d4 100644 --- a/src/omnisharp/logger.ts +++ b/src/omnisharp/logger.ts @@ -9,8 +9,8 @@ export class Logger { private _writer: (message: string) => void; private _prefix: string; - private _indent: string = ' '; private _indentLevel: number = 0; + private _indentSize: number = 4; private _atLineStart: boolean = false; constructor(writer: (message: string) => void, prefix?: string) { @@ -21,8 +21,7 @@ export class Logger { private _appendCore(message: string): void { if (this._atLineStart) { if (this._indentLevel > 0) { - const repeatCount = this._indentLevel; - const indent = this._indent.repeat(repeatCount); + const indent = " ".repeat(this._indentLevel * this._indentSize); this._writer(indent); }