From 23aba8283a2e26773b36da84649a320601689bc4 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 20 Mar 2017 17:16:01 -0700 Subject: [PATCH] Add TSServer Log Collection Commands (#22914) * Add TSServer Log Options Adds support for collecting the TSServer log directly in VS Code * Add enable logging option * Handle case where user is on older version of TS * Rename * Activate on openTSServerLog command * VSCode -> VS Code --- extensions/typescript/package.json | 17 +++ extensions/typescript/package.nls.json | 2 + extensions/typescript/src/typescriptMain.ts | 4 + .../typescript/src/typescriptService.ts | 4 + .../typescript/src/typescriptServiceClient.ts | 101 +++++++++++++++++- 5 files changed, 126 insertions(+), 2 deletions(-) diff --git a/extensions/typescript/package.json b/extensions/typescript/package.json index c5721ef1c0c..65e89389642 100644 --- a/extensions/typescript/package.json +++ b/extensions/typescript/package.json @@ -34,6 +34,7 @@ "onCommand:typescript.selectTypeScriptVersion", "onCommand:javascript.goToProjectConfig", "onCommand:typescript.goToProjectConfig", + "onCommand:typescript.openTsServerLog", "workspaceContains:jsconfig.json", "workspaceContains:tsconfig.json" ], @@ -114,6 +115,17 @@ "default": false, "description": "%typescript.implementationsCodeLens.enabled%" }, + "typescript.tsserver.log": { + "type": "string", + "enum": [ + "off", + "terse", + "normal", + "verbose" + ], + "default": "off", + "description": "%typescript.tsserver.log%" + }, "typescript.tsserver.trace": { "type": "string", "enum": [ @@ -296,6 +308,11 @@ "command": "javascript.goToProjectConfig", "title": "%javascript.goToProjectConfig.title%", "category": "JavaScript" + }, + { + "command": "typescript.openTsServerLog", + "title": "%typescript.openTsServerLog.title%", + "category": "TypeScript" } ], "menus": { diff --git a/extensions/typescript/package.nls.json b/extensions/typescript/package.nls.json index 9746cfc13a4..a96e74dc762 100644 --- a/extensions/typescript/package.nls.json +++ b/extensions/typescript/package.nls.json @@ -7,6 +7,7 @@ "typescript.tsdk_version.desc": "Specifies the version of the tsserver. Only necessary if the tsserver is not installed using npm.", "typescript.disableAutomaticTypeAcquisition": "Disables automatic type acquisition. Requires TypeScript >= 2.0.6 and a restart after changing it.", "typescript.check.tscVersion": "Check if a global install TypeScript compiler (e.g. tsc) differs from the used TypeScript language service.", + "typescript.tsserver.log": "Enables logging of the TS server to a file.", "typescript.tsserver.trace": "Enables tracing of messages sent to the TS server.", "typescript.tsserver.experimentalAutoBuild": "Enables experimental auto build. Requires 1.9 dev or 2.x tsserver version and a restart of VS Code after changing it.", "typescript.validate.enable": "Enable/disable TypeScript validation.", @@ -29,5 +30,6 @@ "javascript.goToProjectConfig.title": "Go to Project Configuration", "typescript.referencesCodeLens.enabled": "Enable/disable references CodeLens.", "typescript.implementationsCodeLens.enabled": "Enable/disable implementations CodeLens.", + "typescript.openTsServerLog.title": "Open TS Server log file", "typescript.selectTypeScriptVersion.title": "Select TypeScript Version" } diff --git a/extensions/typescript/src/typescriptMain.ts b/extensions/typescript/src/typescriptMain.ts index 4dee65fa959..06969028436 100644 --- a/extensions/typescript/src/typescriptMain.ts +++ b/extensions/typescript/src/typescriptMain.ts @@ -104,6 +104,10 @@ export function activate(context: ExtensionContext): void { client.onVersionStatusClicked(); })); + context.subscriptions.push(commands.registerCommand('typescript.openTsServerLog', () => { + client.openTsServerLogFile(); + })); + context.subscriptions.push( languages.registerCompletionItemProvider(selector, new JsDocCompletionHelper(client), '*')); diff --git a/extensions/typescript/src/typescriptService.ts b/extensions/typescript/src/typescriptService.ts index fc191c414c1..289c227daf3 100644 --- a/extensions/typescript/src/typescriptService.ts +++ b/extensions/typescript/src/typescriptService.ts @@ -57,6 +57,10 @@ export class API { public has220Features(): boolean { return semver.gte(this._version, '2.2.0'); } + + public has222Features(): boolean { + return semver.gte(this._version, '2.2.2'); + } } export interface ITypescriptServiceClient { diff --git a/extensions/typescript/src/typescriptServiceClient.ts b/extensions/typescript/src/typescriptServiceClient.ts index 81566df7932..fd230ab3307 100644 --- a/extensions/typescript/src/typescriptServiceClient.ts +++ b/extensions/typescript/src/typescriptServiceClient.ts @@ -8,6 +8,7 @@ import * as cp from 'child_process'; import * as path from 'path'; import * as fs from 'fs'; +import * as os from 'os'; import * as electron from './utils/electron'; import { Reader } from './utils/wireProtocol'; @@ -47,7 +48,9 @@ interface IPackageInfo { } enum Trace { - Off, Messages, Verbose + Off, + Messages, + Verbose } namespace Trace { @@ -66,6 +69,43 @@ namespace Trace { } } +enum TsServerLogLevel { + Off, + Normal, + Terse, + Verbose, +} + +namespace TsServerLogLevel { + export function fromString(value: string): TsServerLogLevel { + switch (value && value.toLowerCase()) { + case 'normal': + return TsServerLogLevel.Normal; + case 'terse': + return TsServerLogLevel.Terse; + case 'verbose': + return TsServerLogLevel.Verbose; + case 'off': + default: + return TsServerLogLevel.Off; + } + } + + export function toString(value: TsServerLogLevel): string { + switch (value) { + case TsServerLogLevel.Normal: + return 'normal'; + case TsServerLogLevel.Terse: + return 'terse'; + case TsServerLogLevel.Verbose: + return 'verbose'; + case TsServerLogLevel.Off: + default: + return 'off'; + } + } +} + enum MessageAction { useLocal, useBundled, @@ -84,7 +124,6 @@ interface MyMessageItem extends MessageItem { export default class TypeScriptServiceClient implements ITypescriptServiceClient { - private static useWorkspaceTsdkStorageKey = 'typescript.useWorkspaceTsdk'; private static tsdkMigratedStorageKey = 'typescript.tsdkMigrated'; @@ -104,6 +143,8 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient private _experimentalAutoBuild: boolean; private trace: Trace; private _output: OutputChannel; + private tsServerLogFile: string | null = null; + private tsServerLogLevel: TsServerLogLevel = TsServerLogLevel.Off; private servicePromise: Promise | null; private lastError: Error | null; private reader: Reader; @@ -156,6 +197,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient this._apiVersion = new API('1.0.0'); this._checkGlobalTSCVersion = true; this.trace = this.readTrace(); + this.tsServerLogLevel = this.readTsServerLogLevel(); disposables.push(workspace.onDidChangeConfiguration(() => { this.trace = this.readTrace(); let oldglobalTsdk = this.globalTsdk; @@ -222,6 +264,11 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient return result; } + private readTsServerLogLevel(): TsServerLogLevel { + const setting = workspace.getConfiguration().get('typescript.tsserver.log', 'off'); + return TsServerLogLevel.fromString(setting); + } + public get experimentalAutoBuild(): boolean { return this._experimentalAutoBuild; } @@ -458,6 +505,15 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient this.cancellationPipeName = electron.getPipeName(`tscancellation-${electron.makeRandomHexString(20)}`); args.push('--cancellationPipeName', this.cancellationPipeName + '*'); } + + if (this.apiVersion.has222Features()) { + if (this.tsServerLogLevel !== TsServerLogLevel.Off) { + this.tsServerLogFile = path.join(os.tmpdir(), `vscode-tsserver-${electron.makeRandomHexString(10)}.log`); + args.push('--logVerbosity', TsServerLogLevel.toString(this.tsServerLogLevel)); + args.push('--logFile', this.tsServerLogFile); + } + } + electron.fork(modulePath, args, options, (err: any, childProcess: cp.ChildProcess) => { if (err) { this.lastError = err; @@ -583,6 +639,47 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient }); } + public openTsServerLogFile(): Thenable { + if (!this.apiVersion.has222Features()) { + return window.showErrorMessage( + localize( + 'typescript.openTsServerLog.notSupported', + 'TS Server logging requires TS 2.2.2+')) + .then(() => false); + } + + if (this.tsServerLogLevel === TsServerLogLevel.Off) { + return window.showErrorMessage( + localize( + 'typescript.openTsServerLog.loggingNotEnabled', + 'TS Server logging is off. Please set `typescript.tsserver.log` and reload VS Code to enable logging'), + { + title: localize( + 'typescript.openTsServerLog.enableAndReloadOption', + 'Enable logging and reload VS Code'), + }) + .then(selection => { + if (selection) { + return workspace.getConfiguration().update('typescript.tsserver.log', 'verbose', true).then(() => { + commands.executeCommand('workbench.action.reloadWindow'); + return false; + }); + } + return false; + }); + } + + if (!this.tsServerLogFile) { + return window.showWarningMessage(localize( + 'typescript.openTsServerLog.noLogFile', + 'TS Server has not started logging.')).then(() => false); + } + + return workspace.openTextDocument(this.tsServerLogFile) + .then(doc => window.showTextDocument(doc, window.activeTextEditor ? window.activeTextEditor.viewColumn : undefined)) + .then(editor => !!editor); + } + private serviceStarted(resendModels: boolean): void { let configureOptions: Proto.ConfigureRequestArguments = { hostInfo: 'vscode' -- GitLab