src/language: adjust panic trace capture logic
Use '[Info - ' or '[Warning - ' or '[Error - ' as the marker
for the end of the panic trace.
Fixes golang/vscode-go#3248
Change-Id: I3aabc0292855f63ceffeea5c09b59e4e0253e95b
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/571316
Commit-Queue: Hyang-Ah Hana Kim <hyangah@gmail.com>
kokoro-CI: kokoro <noreply+kokoro@google.com>
Reviewed-by: Suzy Mueller <suzmue@golang.org>
diff --git a/extension/src/language/goLanguageServer.ts b/extension/src/language/goLanguageServer.ts
index 9f5352f..1f32c3c 100644
--- a/extension/src/language/goLanguageServer.ts
+++ b/extension/src/language/goLanguageServer.ts
@@ -1530,7 +1530,6 @@
enum GoplsFailureModes {
NO_GOPLS_LOG = 'no gopls log',
EMPTY_PANIC_TRACE = 'empty panic trace',
- INCOMPLETE_PANIC_TRACE = 'incomplete panic trace',
INCORRECT_COMMAND_USAGE = 'incorrect gopls command usage',
UNRECOGNIZED_CRASH_PATTERN = 'unrecognized crash pattern'
}
@@ -1544,34 +1543,40 @@
const panicMsgBegin = logs.lastIndexOf('panic: ');
if (panicMsgBegin > -1) {
// panic message was found.
- const panicMsgEnd = logs.indexOf('Connection to server got closed.', panicMsgBegin);
+ let panicTrace = logs.substr(panicMsgBegin);
+ const panicMsgEnd = panicTrace.search(/\[(Info|Warning|Error)\s+-\s+/);
if (panicMsgEnd > -1) {
- const panicTrace = logs.substr(panicMsgBegin, panicMsgEnd - panicMsgBegin);
- const filePattern = /(\S+\.go):\d+/;
- const sanitized = panicTrace
- .split('\n')
- .map((line: string) => {
- // Even though this is a crash from gopls, the file path
- // can contain user names and user's filesystem directory structure.
- // We can still locate the corresponding file if the file base is
- // available because the full package path is part of the function
- // name. So, leave only the file base.
- const m = line.match(filePattern);
- if (!m) {
- return line;
- }
- const filePath = m[1];
- const fileBase = path.basename(filePath);
- return line.replace(filePath, ' ' + fileBase);
- })
- .join('\n');
-
- if (sanitized) {
- return { sanitizedLog: sanitized };
- }
- return { failureReason: GoplsFailureModes.EMPTY_PANIC_TRACE };
+ panicTrace = panicTrace.substr(0, panicMsgEnd);
}
- return { failureReason: GoplsFailureModes.INCOMPLETE_PANIC_TRACE };
+ const filePattern = /(\S+\.go):\d+/;
+ const sanitized = panicTrace
+ .split('\n')
+ .map((line: string) => {
+ // Even though this is a crash from gopls, the file path
+ // can contain user names and user's filesystem directory structure.
+ // We can still locate the corresponding file if the file base is
+ // available because the full package path is part of the function
+ // name. So, leave only the file base.
+ const m = line.match(filePattern);
+ if (!m) {
+ return line;
+ }
+ const filePath = m[1];
+ const fileBase = path.basename(filePath);
+ return line.replace(filePath, ' ' + fileBase);
+ })
+ .join('\n');
+
+ if (sanitized) {
+ return { sanitizedLog: sanitized };
+ }
+ return { failureReason: GoplsFailureModes.EMPTY_PANIC_TRACE };
+ }
+ // Capture Fatal
+ // foo.go:1: the last message (caveat - we capture only the first log line)
+ const m = logs.match(/(^\S+\.go:\d+:.*$)/gm);
+ if (m && m.length > 0) {
+ return { sanitizedLog: m[0].toString() };
}
const initFailMsgBegin = logs.lastIndexOf('gopls client:');
if (initFailMsgBegin > -1) {
@@ -1590,13 +1595,6 @@
if (logs.lastIndexOf('Usage:') > -1) {
return { failureReason: GoplsFailureModes.INCORRECT_COMMAND_USAGE };
}
- // Capture Fatal
- // foo.go:1: the last message (caveat - we capture only the first log line)
- const m = logs.match(/(^\S+\.go:\d+:.*$)/gm);
- if (m && m.length > 0) {
- return { sanitizedLog: m[0].toString() };
- }
-
return { failureReason: GoplsFailureModes.UNRECOGNIZED_CRASH_PATTERN };
}
@@ -1664,6 +1662,6 @@
} catch (e) {
const duration = new Date().getTime() - start.getTime();
console.log(`gopls stats -anon failed: ${JSON.stringify(e)}`);
- return `gopls stats -anon failed after running for ${duration}ms`; // e may contain user information. don't include in the report.
+ return `gopls stats -anon failed after ${duration} ms. Please check if gopls is killed by OS.`;
}
}
diff --git a/extension/test/gopls/report.test.ts b/extension/test/gopls/report.test.ts
index 4cabab9..186378b 100644
--- a/extension/test/gopls/report.test.ts
+++ b/extension/test/gopls/report.test.ts
@@ -26,9 +26,14 @@
want: sanitizedTraceFromIssueVSCodeGo572LSP317
},
{
+ name: 'panic trace 2024 March',
+ in: trace2024MarchPanic,
+ want: sanitizedTrace2024MarchPanic
+ },
+ {
name: 'incomplete panic trace',
- in: 'panic: \nsecret\n',
- wantReason: 'incomplete panic trace'
+ in: 'panic: \ntruncated\n',
+ want: 'panic: \ntruncated\n'
},
{
name: 'incomplete initialization error message',
@@ -42,7 +47,7 @@
assert.strictEqual(
JSON.stringify(sanitizedLog),
JSON.stringify(tc.want),
- `sanitizeGoplsTrace(${tc.name}) returned unexpected sanitizedLog result`
+ `sanitizeGoplsTrace(${tc.name}) returned unexpected sanitizedLog result - ${sanitizedLog}`
);
assert.strictEqual(
failureReason,
@@ -315,7 +320,7 @@
handler.go:103 +0x86
created by golang.org/x/tools/internal/jsonrpc2.AsyncHandler.func1
handler.go:100 +0x171
-[Info - 12:50:26 PM] `;
+`;
const traceFromIssueVSCodeGo572LSP317 = `
[Error - 12:20:35 PM] Stopping server failed
@@ -335,3 +340,47 @@
const sanitizedTraceFromIssueVSCodeGo572LSP317 = `gopls client: couldn't create connection to server.
Message: Socket closed before the connection was established
Code: -32099 `;
+
+const trace2024MarchPanic = `
+[Info - 9:58:40 AM]
+true
+[Error - 9:58:40 AM] gopls client: couldn't create connection to server.
+ Message: Pending response rejected since connection got disposed
+ Code: -32097
+panic: crash
+
+goroutine 1 [running]:
+golang.org/x/tools/gopls/internal/cmd.(*Serve).Run(0xc000486310?, {0xc0000b8090?, 0x0?}, {0x0?, 0x0?, 0x0?})
+ /Users/Gopher/projects/tools/gopls/internal/cmd/serve.go:81 +0x25
+golang.org/x/tools/internal/tool.Run({0x1012d048, 0xc00019c3f0}, 0xc000486310, {0x1012f9e0, 0xc000159b40}, {0xc0000b8090, 0x0, 0x0})
+ /Users/Gopher/projects/tools/internal/tool/tool.go:192 +0x691
+golang.org/x/tools/gopls/internal/cmd.(*Application).Run(0xc000159b00, {0x1012d010, 0x107d9840}, {0xc0000b8090, 0x0, 0x0})
+ /Users/Gopher/projects/tools/gopls/internal/cmd/cmd.go:240 +0x147
+golang.org/x/tools/internal/tool.Run({0x1012d010, 0x107d9840}, 0xc0004862a0, {0x1012f3a0, 0xc000159b00}, {0xc0000b8060, 0x4, 0x4})
+ /Users/Gopher/projects/tools/internal/tool/tool.go:192 +0x691
+golang.org/x/tools/internal/tool.Main({0x1012d010, 0x107d9840}, {0x1012f3a0, 0xc000159b00}, {0xc0000b8060, 0x4, 0x4})
+ /Users/Gopher/projects/tools/internal/tool/tool.go:93 +0x12a
+main.main()
+ /Users/Gopher/projects/tools/gopls/main.go:34 +0x109
+[Error - 9:58:49 AM]
+[Error - 9:58:49 AM] gopls client: couldn't create connection to server.
+ Message: Pending response rejected since connection got disposed
+ Code: -32097
+Error starting language server: Error: Pending response rejected since connection got disposed`;
+
+const sanitizedTrace2024MarchPanic = `panic: crash
+
+goroutine 1 [running]:
+golang.org/x/tools/gopls/internal/cmd.(*Serve).Run(0xc000486310?, {0xc0000b8090?, 0x0?}, {0x0?, 0x0?, 0x0?})
+ serve.go:81 +0x25
+golang.org/x/tools/internal/tool.Run({0x1012d048, 0xc00019c3f0}, 0xc000486310, {0x1012f9e0, 0xc000159b40}, {0xc0000b8090, 0x0, 0x0})
+ tool.go:192 +0x691
+golang.org/x/tools/gopls/internal/cmd.(*Application).Run(0xc000159b00, {0x1012d010, 0x107d9840}, {0xc0000b8090, 0x0, 0x0})
+ cmd.go:240 +0x147
+golang.org/x/tools/internal/tool.Run({0x1012d010, 0x107d9840}, 0xc0004862a0, {0x1012f3a0, 0xc000159b00}, {0xc0000b8060, 0x4, 0x4})
+ tool.go:192 +0x691
+golang.org/x/tools/internal/tool.Main({0x1012d010, 0x107d9840}, {0x1012f3a0, 0xc000159b00}, {0xc0000b8060, 0x4, 0x4})
+ tool.go:93 +0x12a
+main.main()
+ main.go:34 +0x109
+`;