mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-24 12:19:20 +00:00
Add telemetry trace support to TypeScript
This commit is contained in:
@@ -16,6 +16,7 @@ function isCancellationToken(value: any): value is vscode.CancellationToken {
|
||||
|
||||
interface RequestArgs {
|
||||
readonly file?: unknown;
|
||||
readonly $traceId?: unknown;
|
||||
}
|
||||
|
||||
export class TSServerRequestCommand implements Command {
|
||||
@@ -31,11 +32,18 @@ export class TSServerRequestCommand implements Command {
|
||||
}
|
||||
if (args && typeof args === 'object' && !Array.isArray(args)) {
|
||||
const requestArgs = args as RequestArgs;
|
||||
let newArgs: any = undefined;
|
||||
if (requestArgs.file instanceof vscode.Uri) {
|
||||
newArgs = { ...args };
|
||||
const client = this.lazyClientHost.value.serviceClient;
|
||||
newArgs.file = client.toOpenTsFilePath(requestArgs.file);
|
||||
const hasFile = requestArgs.file instanceof vscode.Uri;
|
||||
const hasTraceId = typeof requestArgs.$traceId === 'string';
|
||||
if (hasFile || hasTraceId) {
|
||||
const newArgs = { ...args };
|
||||
if (hasFile) {
|
||||
const client = this.lazyClientHost.value.serviceClient;
|
||||
newArgs.file = client.toOpenTsFilePath(requestArgs.file);
|
||||
}
|
||||
if (hasTraceId) {
|
||||
const telemetryReporter = this.lazyClientHost.value.serviceClient.telemetryReporter;
|
||||
telemetryReporter.logTraceEvent('TSServerRequestCommand.execute', requestArgs.$traceId, JSON.stringify({ command }));
|
||||
}
|
||||
args = newArgs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ export interface TelemetryProperties {
|
||||
|
||||
export interface TelemetryReporter {
|
||||
logTelemetry(eventName: string, properties?: TelemetryProperties): void;
|
||||
logTraceEvent(tracePoint: string, correlationId: string, command?: string): void;
|
||||
}
|
||||
|
||||
export class VSCodeTelemetryReporter implements TelemetryReporter {
|
||||
@@ -34,4 +35,27 @@ export class VSCodeTelemetryReporter implements TelemetryReporter {
|
||||
|
||||
reporter.postEventObj(eventName, properties);
|
||||
}
|
||||
|
||||
public logTraceEvent(point: string, id: string, data?: string): void {
|
||||
const event: { point: string; id: string; data?: string | undefined } = {
|
||||
point,
|
||||
id
|
||||
};
|
||||
if (data) {
|
||||
event.data = data;
|
||||
}
|
||||
|
||||
/* __GDPR__
|
||||
"tsServerRequest.trace" : {
|
||||
"owner": "dirkb",
|
||||
"${include}": [
|
||||
"${TypeScriptCommonProperties}"
|
||||
],
|
||||
"point" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", comment: "The trace point." },
|
||||
"id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", comment: "The traceId is used to correlate the request with other trace points." },
|
||||
"data": { "classification": "SystemMetaData", "purpose": "FeatureInsight", comment: "Additional data" }
|
||||
}
|
||||
*/
|
||||
this.logTelemetry('typeScriptExtension.trace', event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import { nulToken } from '../../utils/cancellation';
|
||||
|
||||
const NoopTelemetryReporter = new class implements TelemetryReporter {
|
||||
logTelemetry(): void { /* noop */ }
|
||||
logTraceEvent(): void { /* noop */ }
|
||||
dispose(): void { /* noop */ }
|
||||
};
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ export interface CallbackItem<R> {
|
||||
readonly onError: (err: Error) => void;
|
||||
readonly queuingStartTime: number;
|
||||
readonly isAsync: boolean;
|
||||
readonly traceId?: string | undefined;
|
||||
}
|
||||
|
||||
export class CallbackMap<R extends Proto.Response> {
|
||||
@@ -43,6 +44,10 @@ export class CallbackMap<R extends Proto.Response> {
|
||||
return callback;
|
||||
}
|
||||
|
||||
public peek(seq: number): CallbackItem<ServerResponse.Response<R> | undefined> | undefined {
|
||||
return this._callbacks.get(seq) ?? this._asyncCallbacks.get(seq);
|
||||
}
|
||||
|
||||
private delete(seq: number) {
|
||||
if (!this._callbacks.delete(seq)) {
|
||||
this._asyncCallbacks.delete(seq);
|
||||
|
||||
@@ -185,6 +185,10 @@ export class SingleTsServer extends Disposable implements ITypeScriptServer {
|
||||
|
||||
private tryCancelRequest(request: Proto.Request, command: string): boolean {
|
||||
const seq = request.seq;
|
||||
const callback = this._callbacks.peek(seq);
|
||||
if (callback?.traceId !== undefined) {
|
||||
this._telemetryReporter.logTraceEvent('TSServerRequest.cancel', callback.traceId, JSON.stringify({ command, cancelled: true }));
|
||||
}
|
||||
try {
|
||||
if (this._requestQueue.tryDeletePendingRequest(seq)) {
|
||||
this.logTrace(`Canceled request with sequence number ${seq}`);
|
||||
@@ -206,7 +210,9 @@ export class SingleTsServer extends Disposable implements ITypeScriptServer {
|
||||
if (!callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback.traceId !== undefined) {
|
||||
this._telemetryReporter.logTraceEvent('TSServerRequest.response', callback.traceId, JSON.stringify({ command: response.command, success: response.success, performanceData: response.performanceData }));
|
||||
}
|
||||
this._tracer.traceResponse(this._serverId, response, callback);
|
||||
if (response.success) {
|
||||
callback.onSuccess(response);
|
||||
@@ -229,7 +235,7 @@ export class SingleTsServer extends Disposable implements ITypeScriptServer {
|
||||
let result: Promise<ServerResponse.Response<Proto.Response>> | undefined;
|
||||
if (executeInfo.expectsResult) {
|
||||
result = new Promise<ServerResponse.Response<Proto.Response>>((resolve, reject) => {
|
||||
this._callbacks.add(request.seq, { onSuccess: resolve as () => ServerResponse.Response<Proto.Response> | undefined, onError: reject, queuingStartTime: Date.now(), isAsync: executeInfo.isAsync }, executeInfo.isAsync);
|
||||
this._callbacks.add(request.seq, { onSuccess: resolve as () => ServerResponse.Response<Proto.Response> | undefined, onError: reject, queuingStartTime: Date.now(), isAsync: executeInfo.isAsync, traceId: request.arguments?.$traceId }, executeInfo.isAsync);
|
||||
|
||||
if (executeInfo.token) {
|
||||
|
||||
@@ -263,6 +269,10 @@ export class SingleTsServer extends Disposable implements ITypeScriptServer {
|
||||
}
|
||||
|
||||
this._requestQueue.enqueue(requestInfo);
|
||||
if (typeof args.$traceId === 'string') {
|
||||
const queueLength = this._requestQueue.length - 1;
|
||||
this._telemetryReporter.logTraceEvent('TSServerRequest.enqueue', args.$traceId, JSON.stringify({ command, queueLength }));
|
||||
}
|
||||
this.sendNextRequests();
|
||||
|
||||
return [result];
|
||||
@@ -287,6 +297,9 @@ export class SingleTsServer extends Disposable implements ITypeScriptServer {
|
||||
|
||||
try {
|
||||
this.write(serverRequest);
|
||||
if (typeof serverRequest.arguments?.$traceId === 'string') {
|
||||
this._telemetryReporter.logTraceEvent('TSServerRequest.send', serverRequest.arguments.$traceId, JSON.stringify({ command: serverRequest.command }));
|
||||
}
|
||||
} catch (err) {
|
||||
const callback = this.fetchCallback(serverRequest.seq);
|
||||
callback?.onError(err);
|
||||
|
||||
Reference in New Issue
Block a user