未验证 提交 27e2e92a 编写于 作者: A Andrew Casey 提交者: GitHub

Clean up CallstackOrException telemetry in typescript-language-features (#96108)

One was actually SystemMetaData, all others were either dropped or
replaced with sanitized versions classifiable as SystemMetaData.
上级 3a548def
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import type * as Proto from '../protocol'; import type * as Proto from '../protocol';
import { escapeRegExp } from '../utils/regexp';
import { TypeScriptVersion } from '../utils/versionProvider'; import { TypeScriptVersion } from '../utils/versionProvider';
...@@ -14,8 +13,8 @@ export class TypeScriptServerError extends Error { ...@@ -14,8 +13,8 @@ export class TypeScriptServerError extends Error {
version: TypeScriptVersion, version: TypeScriptVersion,
response: Proto.Response response: Proto.Response
): TypeScriptServerError { ): TypeScriptServerError {
const parsedResult = TypeScriptServerError.parseErrorText(version, response); const parsedResult = TypeScriptServerError.parseErrorText(response);
return new TypeScriptServerError(serverId, version, response, parsedResult?.message, parsedResult?.stack); return new TypeScriptServerError(serverId, version, response, parsedResult?.message, parsedResult?.stack, parsedResult?.sanitizedStack);
} }
private constructor( private constructor(
...@@ -23,7 +22,8 @@ export class TypeScriptServerError extends Error { ...@@ -23,7 +22,8 @@ export class TypeScriptServerError extends Error {
public readonly version: TypeScriptVersion, public readonly version: TypeScriptVersion,
private readonly response: Proto.Response, private readonly response: Proto.Response,
public readonly serverMessage: string | undefined, public readonly serverMessage: string | undefined,
public readonly serverStack: string | undefined public readonly serverStack: string | undefined,
private readonly sanitizedStack: string | undefined
) { ) {
super(`<${serverId}> TypeScript Server Error (${version.displayName})\n${serverMessage}\n${serverStack}`); super(`<${serverId}> TypeScript Server Error (${version.displayName})\n${serverMessage}\n${serverStack}`);
} }
...@@ -33,19 +33,17 @@ export class TypeScriptServerError extends Error { ...@@ -33,19 +33,17 @@ export class TypeScriptServerError extends Error {
public get serverCommand() { return this.response.command; } public get serverCommand() { return this.response.command; }
public get telemetry() { public get telemetry() {
// The "sanitizedstack" has been purged of error messages, paths, and file names (other than tsserver)
// and, thus, can be classified as SystemMetaData, rather than CallstackOrException.
/* __GDPR__FRAGMENT__ /* __GDPR__FRAGMENT__
"TypeScriptRequestErrorProperties" : { "TypeScriptRequestErrorProperties" : {
"command" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "command" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"message" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }, "sanitizedstack" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" },
"stack" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
"errortext" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }
} }
*/ */
return { return {
command: this.serverCommand, command: this.serverCommand,
message: this.serverMessage || '', sanitizedstack: this.sanitizedStack || '',
stack: this.serverStack || '',
errortext: this.serverErrorText || '',
} as const; } as const;
} }
...@@ -53,27 +51,20 @@ export class TypeScriptServerError extends Error { ...@@ -53,27 +51,20 @@ export class TypeScriptServerError extends Error {
* Given a `errorText` from a tsserver request indicating failure in handling a request, * Given a `errorText` from a tsserver request indicating failure in handling a request,
* prepares a payload for telemetry-logging. * prepares a payload for telemetry-logging.
*/ */
private static parseErrorText(version: TypeScriptVersion, response: Proto.Response) { private static parseErrorText(response: Proto.Response) {
const errorText = response.message; const errorText = response.message;
if (errorText) { if (errorText) {
const errorPrefix = 'Error processing request. '; const errorPrefix = 'Error processing request. ';
if (errorText.startsWith(errorPrefix)) { if (errorText.startsWith(errorPrefix)) {
let prefixFreeErrorText = errorText.substr(errorPrefix.length); const prefixFreeErrorText = errorText.substr(errorPrefix.length);
// Prior to https://github.com/microsoft/TypeScript/pull/32785, this error
// returned and excessively long and detailed list of paths. Since server-side
// filtering doesn't have sufficient granularity to drop these specific
// messages, we sanitize them here.
if (prefixFreeErrorText.indexOf('Could not find sourceFile') >= 0) {
prefixFreeErrorText = prefixFreeErrorText.replace(/ in \[[^\]]*\]/g, '');
}
const newlineIndex = prefixFreeErrorText.indexOf('\n'); const newlineIndex = prefixFreeErrorText.indexOf('\n');
if (newlineIndex >= 0) { if (newlineIndex >= 0) {
// Newline expected between message and stack. // Newline expected between message and stack.
const stack = prefixFreeErrorText.substring(newlineIndex + 1);
return { return {
message: prefixFreeErrorText.substring(0, newlineIndex), message: prefixFreeErrorText.substring(0, newlineIndex),
stack: TypeScriptServerError.normalizeMessageStack(version, prefixFreeErrorText.substring(newlineIndex + 1)) stack,
sanitizedStack: TypeScriptServerError.sanitizeStack(stack)
}; };
} }
} }
...@@ -82,12 +73,23 @@ export class TypeScriptServerError extends Error { ...@@ -82,12 +73,23 @@ export class TypeScriptServerError extends Error {
} }
/** /**
* Try to replace full TS Server paths with 'tsserver.js' so that we don't have to post process the data as much * Drop everything but ".js" and line/column numbers (though retain "tsserver" if that's the filename).
*/ */
private static normalizeMessageStack(version: TypeScriptVersion, message: string | undefined) { private static sanitizeStack(message: string | undefined) {
if (!message) { if (!message) {
return ''; return '';
} }
return message.replace(new RegExp(`${escapeRegExp(version.path)}[/\\\\]tsserver.js:`, 'gi'), 'tsserver.js:'); const regex = /(tsserver)?(\.(?:ts|tsx|js|jsx)(?::\d+(?::\d+))?)\)?$/igm;
let serverStack = '';
while (true) {
const match = regex.exec(message);
if (!match) {
break;
}
// [1] is 'tsserver' or undefined
// [2] is '.js:{line_number}:{column_number}'
serverStack += `${match[1] || 'suppressed'}${match[2]}\n`;
}
return serverStack;
} }
} }
...@@ -391,10 +391,12 @@ export default class TypeScriptServiceClient extends Disposable implements IType ...@@ -391,10 +391,12 @@ export default class TypeScriptServiceClient extends Disposable implements IType
if (code === null || typeof code === 'undefined') { if (code === null || typeof code === 'undefined') {
this.info('TSServer exited'); this.info('TSServer exited');
} else { } else {
// In practice, the exit code is an integer with no ties to any identity,
// so it can be classified as SystemMetaData, rather than CallstackOrException.
this.error(`TSServer exited with code: ${code}`); this.error(`TSServer exited with code: ${code}`);
/* __GDPR__ /* __GDPR__
"tsserver.exitWithCode" : { "tsserver.exitWithCode" : {
"code" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" }, "code" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" },
"${include}": [ "${include}": [
"${TypeScriptCommonProperties}" "${TypeScriptCommonProperties}"
] ]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册