Skip to content

Commit 292b78f

Browse files
committed
[release] src/goLanguageServer.ts: include sanitized trace to issue report
Many automated gopls crash reports come with empty stack trace and provides little information. This CL tries to extract the stack trace from panic or the initialize error message. The stack trace is from the gopls binary itself so there is not much confidential except the package file paths. Remove those file paths and leave only the file base name parts. The package paths are included in the function name parts, so we still can locate the corresponding files in the gopls repository. If we fail to sanitize, do not include any stack trace and ask users to include it manually. Also, includes the language server binary flag, which will help with identifying crashes caused by incorrect gopls args. B Change-Id: I5fcab48b28b7adb0adf369af4227c29ca646b2a3 Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/256878 Trust: Hyang-Ah Hana Kim <[email protected]> Run-TryBot: Hyang-Ah Hana Kim <[email protected]> TryBot-Result: kokoro <[email protected]> Reviewed-by: Rebecca Stambler <[email protected]> (cherry picked from commit 9ebcc1f) Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/257604
1 parent f78c016 commit 292b78f

File tree

2 files changed

+402
-5
lines changed

2 files changed

+402
-5
lines changed

src/goLanguageServer.ts

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,21 +1045,31 @@ You will be asked to provide additional information and logs, so PLEASE READ THE
10451045
break;
10461046
}
10471047
const usersGoplsVersion = await getLocalGoplsVersion(latestConfig);
1048+
// TODO(hakim): If gopls version is too old, ask users to update it.
1049+
const settings = latestConfig.flags.join(' ');
10481050
const title = `gopls: automated issue report (${errKind})`;
1051+
const sanitizedLog = collectGoplsLog();
1052+
const goplsLog = (sanitizedLog) ?
1053+
`<pre>${sanitizedLog}</pre>` :
1054+
`
1055+
Please attach the stack trace from the crash.
1056+
A window with the error message should have popped up in the lower half of your screen.
1057+
Please copy the stack trace and error messages from that window and paste it in this issue.
1058+
1059+
<PASTE STACK TRACE HERE>
1060+
`;
1061+
10491062
const body = `
10501063
gopls version: ${usersGoplsVersion}
1064+
gopls flags: ${settings}
10511065
10521066
ATTENTION: PLEASE PROVIDE THE DETAILS REQUESTED BELOW.
10531067
10541068
Describe what you observed.
10551069
10561070
<ANSWER HERE>
10571071
1058-
Please attach the stack trace from the crash.
1059-
A window with the error message should have popped up in the lower half of your screen.
1060-
Please copy the stack trace from that window and paste it in this issue.
1061-
1062-
<PASTE STACK TRACE HERE>
1072+
${goplsLog}
10631073
10641074
OPTIONAL: If you would like to share more information, you can attach your complete gopls logs.
10651075
@@ -1106,3 +1116,68 @@ function minutesBetween(a: Date, b: Date): number {
11061116
function msBetween(a: Date, b: Date): number {
11071117
return Math.abs(a.getTime() - b.getTime());
11081118
}
1119+
1120+
function collectGoplsLog(): string {
1121+
serverOutputChannel.show();
1122+
// Find the logs in the output channel. There is no way to read
1123+
// an output channel directly, but we can find the open text
1124+
// document, since we just surfaced the output channel to the user.
1125+
// See https://github.com/microsoft/vscode/issues/65108.
1126+
let logs: string;
1127+
for (const doc of vscode.workspace.textDocuments) {
1128+
if (doc.languageId !== 'Log') {
1129+
continue;
1130+
}
1131+
if (doc.isDirty || doc.isClosed) {
1132+
continue;
1133+
}
1134+
// The document's name should look like 'extension-output-#X'.
1135+
if (doc.fileName.indexOf('extension-output-') === -1) {
1136+
continue;
1137+
}
1138+
logs = doc.getText();
1139+
break;
1140+
}
1141+
return sanitizeGoplsTrace(logs);
1142+
}
1143+
1144+
// capture only panic stack trace and the initialization error message.
1145+
// exported for testing.
1146+
export function sanitizeGoplsTrace(logs?: string): string {
1147+
if (!logs) {
1148+
return '';
1149+
}
1150+
const panicMsgBegin = logs.lastIndexOf('panic: ');
1151+
if (panicMsgBegin > -1) { // panic message was found.
1152+
const panicMsgEnd = logs.indexOf('Connection to server got closed.', panicMsgBegin);
1153+
if (panicMsgEnd > -1) {
1154+
const panicTrace = logs.substr(panicMsgBegin, panicMsgEnd - panicMsgBegin);
1155+
const filePattern = /(\S+\.go):\d+/;
1156+
const sanitized = panicTrace.split('\n').map(
1157+
(line: string) => {
1158+
// Even though this is a crash from gopls, the file path
1159+
// can contain user names and user's filesystem directory structure.
1160+
// We can still locate the corresponding file if the file base is
1161+
// available because the full package path is part of the function
1162+
// name. So, leave only the file base.
1163+
const m = line.match(filePattern);
1164+
if (!m) { return line; }
1165+
const filePath = m[1];
1166+
const fileBase = path.basename(filePath);
1167+
return line.replace(filePath, ' ' + fileBase);
1168+
}
1169+
).join('\n');
1170+
1171+
return sanitized;
1172+
}
1173+
}
1174+
const initFailMsgBegin = logs.lastIndexOf('Starting client failed');
1175+
if (initFailMsgBegin > -1) { // client start failed. Capture up to the 'Code:' line.
1176+
const initFailMsgEnd = logs.indexOf('Code: ', initFailMsgBegin);
1177+
if (initFailMsgEnd > -1) {
1178+
const lineEnd = logs.indexOf('\n', initFailMsgEnd);
1179+
return lineEnd > -1 ? logs.substr(initFailMsgBegin, lineEnd - initFailMsgBegin) : logs.substr(initFailMsgBegin);
1180+
}
1181+
}
1182+
return '';
1183+
}

0 commit comments

Comments
 (0)