diff --git a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts index db53b5cf4d3..4f417c27fbf 100644 --- a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts +++ b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts @@ -30,6 +30,7 @@ import * as typeConverters from './utils/typeConverters'; import TypingsStatus, { AtaProgressReporter } from './utils/typingsStatus'; import * as ProjectStatus from './utils/largeProjectStatus'; import { ActiveJsTsEditorTracker } from './utils/activeJsTsEditorTracker'; +import { LogLevelMonitor } from './utils/logLevelMonitor'; // Style check diagnostics that can be reported as warnings const styleCheckDiagnostics = new Set([ @@ -147,6 +148,7 @@ export default class TypeScriptServiceClientHost extends Disposable { vscode.workspace.onDidChangeConfiguration(this.configurationChanged, this, this._disposables); this.configurationChanged(); + this._register(new LogLevelMonitor(context)); } private registerExtensionLanguageProvider(description: LanguageDescription, onCompletionAccepted: (item: vscode.CompletionItem) => void) { diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index c72375bd348..732851ff317 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -1055,4 +1055,3 @@ class ServerInitializingIndicator extends Disposable { } } } - diff --git a/extensions/typescript-language-features/src/utils/logLevelMonitor.ts b/extensions/typescript-language-features/src/utils/logLevelMonitor.ts new file mode 100644 index 00000000000..7a3c752194e --- /dev/null +++ b/extensions/typescript-language-features/src/utils/logLevelMonitor.ts @@ -0,0 +1,106 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { Disposable } from './dispose'; +import { localize } from '../tsServer/versionProvider'; +import { TsServerLogLevel } from './configuration'; + +export class LogLevelMonitor extends Disposable { + + private static readonly logLevelConfigKey = 'typescript.tsserver.log'; + private static readonly logLevelChangedStorageKey = 'typescript.tsserver.logLevelChanged'; + private static readonly doNotPromptLogLevelStorageKey = 'typescript.tsserver.doNotPromptLogLevel'; + + constructor(private readonly context: vscode.ExtensionContext) { + super(); + + this._register(vscode.workspace.onDidChangeConfiguration(this.onConfigurationChange, this, this._disposables)); + + if (this.shouldNotifyExtendedLogging()) { + this.notifyExtendedLogging(); + } + } + + private onConfigurationChange(event: vscode.ConfigurationChangeEvent) { + const logLevelChanged = event.affectsConfiguration(LogLevelMonitor.logLevelConfigKey); + if (!logLevelChanged) { + return; + } + this.context.globalState.update(LogLevelMonitor.logLevelChangedStorageKey, new Date()); + } + + private get logLevel(): TsServerLogLevel { + return TsServerLogLevel.fromString(vscode.workspace.getConfiguration().get(LogLevelMonitor.logLevelConfigKey, 'off')); + } + + /** + * Last date change if it exists and can be parsed as a date, + * otherwise undefined. + */ + private get lastLogLevelChange(): Date | undefined { + const lastChange = this.context.globalState.get(LogLevelMonitor.logLevelChangedStorageKey); + + if (lastChange) { + const date = new Date(lastChange); + if (date instanceof Date && !isNaN(date.valueOf())) { + return date; + } + } + return undefined; + } + + private get doNotPrompt(): boolean { + return this.context.globalState.get(LogLevelMonitor.doNotPromptLogLevelStorageKey) || false; + } + + private shouldNotifyExtendedLogging(): boolean { + const lastChangeMilliseconds = this.lastLogLevelChange ? new Date(this.lastLogLevelChange).valueOf() : 0; + const lastChangePlusOneWeek = new Date(lastChangeMilliseconds + /* 7 days in milliseconds */ 86400000 * 7); + + if (!this.doNotPrompt && this.logLevel !== TsServerLogLevel.Off && lastChangePlusOneWeek.valueOf() < Date.now()) { + return true; + } + return false; + } + + private notifyExtendedLogging() { + const enum Choice { + DisableLogging = 0, + DoNotShowAgain = 1 + } + interface Item extends vscode.MessageItem { + readonly choice: Choice; + } + + vscode.window.showInformationMessage( + localize( + 'typescript.extendedLogging.isEnabled', + "TS Server logging is currently enabled which may impact performance."), + { + title: localize( + 'typescript.extendedLogging.disableLogging', + "Disable logging"), + choice: Choice.DisableLogging + }, + { + title: localize( + 'typescript.extendedLogging.doNotShowAgain', + "Don't show again"), + choice: Choice.DoNotShowAgain + }) + .then(selection => { + if (!selection) { + return; + } + if (selection.choice === Choice.DisableLogging) { + return vscode.workspace.getConfiguration().update(LogLevelMonitor.logLevelConfigKey, 'off', true); + } else if (selection.choice === Choice.DoNotShowAgain) { + return this.context.globalState.update(LogLevelMonitor.doNotPromptLogLevelStorageKey, true); + } + return; + }); + } +}