diff --git a/extensions/typescript-language-features/src/tsServer/callbackMap.ts b/extensions/typescript-language-features/src/tsServer/callbackMap.ts index 1484b0ff654..60c9a21675a 100644 --- a/extensions/typescript-language-features/src/tsServer/callbackMap.ts +++ b/extensions/typescript-language-features/src/tsServer/callbackMap.ts @@ -12,6 +12,7 @@ export interface CallbackItem { readonly queuingStartTime: number; readonly isAsync: boolean; readonly traceId?: string | undefined; + readonly command?: string; } export class CallbackMap { diff --git a/extensions/typescript-language-features/src/tsServer/requestQueue.ts b/extensions/typescript-language-features/src/tsServer/requestQueue.ts index e81da742fd5..036f5be9b8e 100644 --- a/extensions/typescript-language-features/src/tsServer/requestQueue.ts +++ b/extensions/typescript-language-features/src/tsServer/requestQueue.ts @@ -60,6 +60,18 @@ export class RequestQueue { return this.queue.shift(); } + public getQueuedCommands(): string[] { + const result: string[] = []; + for (let i = this.queue.length - 1; i >= 0; i--) { + const item = this.queue[i]; + result.push(item.request.command); + if (result.length >= 5) { + break; + } + } + return result; + } + public tryDeletePendingRequest(seq: number): boolean { for (let i = 0; i < this.queue.length; i++) { if (this.queue[i].request.seq === seq) { diff --git a/extensions/typescript-language-features/src/tsServer/server.ts b/extensions/typescript-language-features/src/tsServer/server.ts index cce320d3997..5375834b57c 100644 --- a/extensions/typescript-language-features/src/tsServer/server.ts +++ b/extensions/typescript-language-features/src/tsServer/server.ts @@ -8,7 +8,7 @@ import * as vscode from 'vscode'; import { TypeScriptServiceConfiguration } from '../configuration/configuration'; import { TelemetryReporter } from '../logging/telemetry'; import Tracer from '../logging/tracer'; -import { CallbackMap } from '../tsServer/callbackMap'; +import { CallbackMap, type CallbackItem } from '../tsServer/callbackMap'; import { RequestItem, RequestQueue, RequestQueueingType } from '../tsServer/requestQueue'; import { TypeScriptServerError } from '../tsServer/serverError'; import { ServerResponse, ServerType, TypeScriptRequests } from '../typescriptService'; @@ -235,8 +235,21 @@ export class SingleTsServer extends Disposable implements ITypeScriptServer { let result: Promise> | undefined; if (executeInfo.expectsResult) { result = new Promise>((resolve, reject) => { - this._callbacks.add(request.seq, { onSuccess: resolve as () => ServerResponse.Response | undefined, onError: reject, queuingStartTime: Date.now(), isAsync: executeInfo.isAsync, traceId: request.arguments?.$traceId }, executeInfo.isAsync); - + const item: CallbackItem | undefined> = typeof request.arguments?.$traceId === 'string' + ? { + onSuccess: resolve as () => ServerResponse.Response | undefined, + onError: reject, + queuingStartTime: Date.now(), + isAsync: executeInfo.isAsync, + traceId: request.arguments.$traceId, + command: request.command + } : { + onSuccess: resolve as () => ServerResponse.Response | undefined, + onError: reject, + queuingStartTime: Date.now(), + isAsync: executeInfo.isAsync + }; + this._callbacks.add(request.seq, item, executeInfo.isAsync); if (executeInfo.token) { const cancelViaSAB = isWebAndHasSharedArrayBuffers() @@ -272,13 +285,40 @@ export class SingleTsServer extends Disposable implements ITypeScriptServer { if (args && typeof (args as any).$traceId === 'string') { const queueLength = this._requestQueue.length - 1; const pendingResponses = this._pendingResponses.size; - this._telemetryReporter.logTraceEvent('TSServer.enqueueRequest', (args as any).$traceId, JSON.stringify({ command, queueLength, pendingResponses })); + const data: { command: string; queueLength: number; pendingResponses: number; queuedCommands?: string[]; pendingCommands?: string[] } = { + command: request.command, + queueLength, + pendingResponses + }; + if (queueLength > 0) { + data.queuedCommands = this._requestQueue.getQueuedCommands(); + } + if (pendingResponses > 0) { + data.pendingCommands = this.getPendingCommands(); + } + + this._telemetryReporter.logTraceEvent('TSServer.enqueueRequest', (args as any).$traceId, JSON.stringify(data)); } this.sendNextRequests(); return [result]; } + private getPendingCommands(): string[] { + const result: string[] = []; + for (const seq of this._pendingResponses) { + const callback = this._callbacks.peek(seq); + if (typeof callback?.command !== 'string') { + continue; + } + result.push(callback.command); + if (result.length >= 5) { + break; + } + } + return result; + } + private sendNextRequests(): void { while (this._pendingResponses.size === 0 && this._requestQueue.length > 0) { const item = this._requestQueue.dequeue();