diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index 7345b0c78..f8d810d42 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -59,7 +59,7 @@ import { CopilotCompletionContextFeatures, CopilotCompletionContextProvider } fr import { CustomConfigurationProvider1, getCustomConfigProviders, isSameProviderExtensionId } from './customProviders'; import { DataBinding } from './dataBinding'; import { cachedEditorConfigSettings, getEditorConfigSettings } from './editorConfig'; -import { CppSourceStr, clients, configPrefix, initializeIntervalTimer, updateLanguageConfigurations, usesCrashHandler, watchForCrashes } from './extension'; +import { CppSourceStr, clients, configPrefix, initializeIntervalTimer, isWritingCrashCallStack, updateLanguageConfigurations, usesCrashHandler, watchForCrashes } from './extension'; import { LocalizeStringParams, getLocaleId, getLocalizedString } from './localization'; import { PersistentFolderState, PersistentState, PersistentWorkspaceState } from './persistentState'; import { RequestCancelled, ServerCancelled, createProtocolFilter } from './protocolFilter'; @@ -953,6 +953,8 @@ export class DefaultClient implements Client { public getShowConfigureIntelliSenseButton(): boolean { return this.showConfigureIntelliSenseButton; } public setShowConfigureIntelliSenseButton(show: boolean): void { this.showConfigureIntelliSenseButton = show; } + private lastInvokedLspMessage: string = ""; // e.g. cpptools/hover + /** * don't use this.rootFolder directly since it can be undefined */ @@ -1688,7 +1690,6 @@ export class DefaultClient implements Client { closed: () => { languageClientCrashTimes.push(Date.now()); languageClientCrashedNeedsRestart = true; - telemetry.logLanguageServerEvent("languageClientCrash"); let restart: boolean = true; if (languageClientCrashTimes.length < 5) { void clients.recreateClients(); @@ -1702,6 +1703,26 @@ export class DefaultClient implements Client { void clients.recreateClients(); } } + + // Wait 1 second to allow time for the file watcher to signal a crash call stack write has occurred. + setTimeout(() => { + telemetry.logLanguageServerEvent("languageClientCrash", + { + lastInvokedLspMessage: this.lastInvokedLspMessage + }, + { + restarting: Number(restart), + writingCrashCallStack: Number(isWritingCrashCallStack), + initializingWorkspace: Number(this.model.isInitializingWorkspace.Value), + indexingWorkspace: Number(this.model.isIndexingWorkspace.Value), + parsingWorkspace: Number(this.model.isParsingWorkspace.Value), + parsingFiles: Number(this.model.isParsingFiles.Value), + updatingIntelliSense: Number(this.model.isUpdatingIntelliSense.Value), + runningCodeAnalysis: Number(this.model.isRunningCodeAnalysis.Value) + } + ); + }, 1000); + const message: string = restart ? localize('server.crashed.restart', 'The language server crashed. Restarting...') : localize('server.crashed2', 'The language server crashed 5 times in the last 3 minutes. It will not be restarted.'); @@ -2768,55 +2789,59 @@ export class DefaultClient implements Client { const message: string = notificationBody.status; util.setProgress(util.getProgressExecutableSuccess()); const testHook: TestHook = getTestHook(); - if (message.endsWith("Idle")) { - const status: IntelliSenseStatus = { status: Status.Idle }; - testHook.updateStatus(status); - } else if (message.endsWith("Parsing")) { - this.model.isParsingWorkspace.Value = true; - this.model.isInitializingWorkspace.Value = false; - this.model.isIndexingWorkspace.Value = false; - const status: IntelliSenseStatus = { status: Status.TagParsingBegun }; - testHook.updateStatus(status); - } else if (message.endsWith("Initializing")) { - this.model.isInitializingWorkspace.Value = true; - this.model.isIndexingWorkspace.Value = false; - this.model.isParsingWorkspace.Value = false; - } else if (message.endsWith("Indexing")) { - this.model.isIndexingWorkspace.Value = true; - this.model.isInitializingWorkspace.Value = false; - this.model.isParsingWorkspace.Value = false; - } else if (message.endsWith("files")) { - this.model.isParsingFiles.Value = true; - } else if (message.endsWith("IntelliSense")) { - timeStamp = Date.now(); - this.model.isUpdatingIntelliSense.Value = true; - const status: IntelliSenseStatus = { status: Status.IntelliSenseCompiling }; - testHook.updateStatus(status); - } else if (message.endsWith("IntelliSense done")) { - getOutputChannelLogger().appendLineAtLevel(6, localize("update.intellisense.time", "Update IntelliSense time (sec): {0}", (Date.now() - timeStamp) / 1000)); - this.model.isUpdatingIntelliSense.Value = false; - const status: IntelliSenseStatus = { status: Status.IntelliSenseReady }; - testHook.updateStatus(status); - } else if (message.endsWith("Parsing done")) { // Tag Parser Ready - this.model.isParsingWorkspace.Value = false; - const status: IntelliSenseStatus = { status: Status.TagParsingDone }; - testHook.updateStatus(status); - util.setProgress(util.getProgressParseRootSuccess()); - } else if (message.endsWith("files done")) { - this.model.isParsingFiles.Value = false; - } else if (message.endsWith("Analysis")) { - this.model.isRunningCodeAnalysis.Value = true; - this.model.codeAnalysisTotal.Value = 1; - this.model.codeAnalysisProcessed.Value = 0; - } else if (message.endsWith("Analysis done")) { - this.model.isRunningCodeAnalysis.Value = false; - } else if (message.includes("Squiggles Finished - File name:")) { - const index: number = message.lastIndexOf(":"); - const name: string = message.substring(index + 2); - const status: IntelliSenseStatus = { status: Status.IntelliSenseReady, filename: name }; - testHook.updateStatus(status); - } else if (message.endsWith("No Squiggles")) { - util.setIntelliSenseProgress(util.getProgressIntelliSenseNoSquiggles()); + if (message.startsWith("C_Cpp: ")) { + if (message.endsWith("Idle")) { + const status: IntelliSenseStatus = { status: Status.Idle }; + testHook.updateStatus(status); + } else if (message.endsWith("Parsing")) { + this.model.isParsingWorkspace.Value = true; + this.model.isInitializingWorkspace.Value = false; + this.model.isIndexingWorkspace.Value = false; + const status: IntelliSenseStatus = { status: Status.TagParsingBegun }; + testHook.updateStatus(status); + } else if (message.endsWith("Initializing")) { + this.model.isInitializingWorkspace.Value = true; + this.model.isIndexingWorkspace.Value = false; + this.model.isParsingWorkspace.Value = false; + } else if (message.endsWith("Indexing")) { + this.model.isIndexingWorkspace.Value = true; + this.model.isInitializingWorkspace.Value = false; + this.model.isParsingWorkspace.Value = false; + } else if (message.endsWith("files")) { + this.model.isParsingFiles.Value = true; + } else if (message.endsWith("IntelliSense")) { + timeStamp = Date.now(); + this.model.isUpdatingIntelliSense.Value = true; + const status: IntelliSenseStatus = { status: Status.IntelliSenseCompiling }; + testHook.updateStatus(status); + } else if (message.endsWith("IntelliSense done")) { + getOutputChannelLogger().appendLineAtLevel(6, localize("update.intellisense.time", "Update IntelliSense time (sec): {0}", (Date.now() - timeStamp) / 1000)); + this.model.isUpdatingIntelliSense.Value = false; + const status: IntelliSenseStatus = { status: Status.IntelliSenseReady }; + testHook.updateStatus(status); + } else if (message.endsWith("Parsing done")) { // Tag Parser Ready + this.model.isParsingWorkspace.Value = false; + const status: IntelliSenseStatus = { status: Status.TagParsingDone }; + testHook.updateStatus(status); + util.setProgress(util.getProgressParseRootSuccess()); + } else if (message.endsWith("files done")) { + this.model.isParsingFiles.Value = false; + } else if (message.endsWith("Analysis")) { + this.model.isRunningCodeAnalysis.Value = true; + this.model.codeAnalysisTotal.Value = 1; + this.model.codeAnalysisProcessed.Value = 0; + } else if (message.endsWith("Analysis done")) { + this.model.isRunningCodeAnalysis.Value = false; + } else if (message.includes("Squiggles Finished - File name:")) { + const index: number = message.lastIndexOf(":"); + const name: string = message.substring(index + 2); + const status: IntelliSenseStatus = { status: Status.IntelliSenseReady, filename: name }; + testHook.updateStatus(status); + } else if (message.endsWith("No Squiggles")) { + util.setIntelliSenseProgress(util.getProgressIntelliSenseNoSquiggles()); + } + } else if (message.includes("/")) { + this.lastInvokedLspMessage = message; } } diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index db96623bf..a20d6e100 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -55,6 +55,7 @@ let languageConfigurations: vscode.Disposable[] = []; let intervalTimer: NodeJS.Timeout; let codeActionProvider: vscode.Disposable; export const intelliSenseDisabledError: string = "Do not activate the extension when IntelliSense is disabled."; +export let isWritingCrashCallStack: boolean = false; type VcpkgDatabase = Record; // Stored as
-> [] let vcpkgDbPromise: Promise; @@ -1023,9 +1024,11 @@ export function watchForCrashes(crashDirectory: string): void { return; } const crashDate: Date = new Date(); + isWritingCrashCallStack = true; // Wait 5 seconds to allow time for the crash log to finish being written. setTimeout(() => { + isWritingCrashCallStack = false; fs.readFile(path.resolve(crashDirectory, filename), 'utf8', (err, data) => { void handleCrashFileRead(crashDirectory, filename, crashDate, err, data); });