feat: linkify Java stack traces in text documents (#1654)#1657
Conversation
Add a DocumentLinkProvider that makes Java stack frames clickable in untitled documents and .log files, so a trace pasted from a log/CI/bug report can be navigated to source without an active debug session. Reuses the session-independent resolveSourceUri backend; frames are resolved lazily on click, with a source-scheme allowlist and length/ReDoS guards. Also adds an optional 'Java: Analyze Stack Trace' command that opens a scratch document prefilled from the clipboard.
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
… usage Add three content-free telemetry events (with __GDPR__ annotations) forming an adoption funnel: provideJavaStackTraceLinks (reach, deduped once per document), navigateToJavaStackFrame (click engagement, with documentSource + resolution outcome), and analyzeJavaStackTrace (command entry usage, with prefilledFromClipboard). All dimensions are categorical; the pasted trace text is never recorded. Also bound clipboard scanning length.
…events Simplify to one usage signal (navigateToJavaStackFrame with a documentSource dimension), mirroring the existing handleJavaTerminalLink pattern. Drop the per-document reach event (and its WeakSet) and the manual command event - command invocations are already auto-instrumented by instrumentOperationAsVsCodeCommand.
…ault Add workspaceContains:**/*.java so the passive DocumentLinkProvider is registered as soon as a Java project is opened - without waiting for the user to open a .java file or run a command. This matches exactly the scope where resolveSourceUri can resolve frames to source, so the feature is automatic wherever it can deliver value.
Frame resolution (resolveSourceUri) requires a fully-loaded workspace, so registering the document link provider before jdtls is ready produces links that cannot resolve. Defer provider registration until ServerMode.STANDARD via redhat.java's onDidServerModeChange, mirroring initializeCodeLensProvider. Commands stay registered immediately.
…lick count The single navigateToJavaStackFrame event is enough to measure adoption; the documentSource breakdown is not needed. Remove the dimension, the IStackFrameLinkArgs field, and the categorizeDocumentSource helper.
Drop the `log` language and `**/*.log` selectors so linkification only targets pasted traces in untitled (scratch) documents. A `.log` opened without a Java project can't resolve frames anyway, so scanning them (or every plaintext file) adds no value. Keeps the feature narrow to the two intended paste flows: a new tab and the Analyze Stack Trace command. Copilot-Session: d80e7a97-119d-4f89-a02a-be25b076e806
…rden navigate - Add a commandPalette when-clause (javaLSReady) to java.debug.analyzeStackTrace so it only shows once the Java language server is ready - matching where the linkify provider actually registers, and avoiding a dead-end scratch doc in non-Java windows. - Extract the duplicated frame regex + parsing into stackFrameParser.ts, shared by the terminal and document link providers so matching stays identical. The helper builds a fresh RegExp per call, preserving the terminal provider's no-shared-stateful-RegExp contract. - Wrap resolveSourceUri/navigation in navigateToStackFrame in try/catch (and await the navigation) so a not-ready/restarting language server can't surface an unhandled rejection. Copilot-Session: d80e7a97-119d-4f89-a02a-be25b076e806
There was a problem hiding this comment.
Pull request overview
Adds a new editor surface for Java stack trace navigation by linkifying stack frames in untitled (scratch) documents, reusing the existing resolveSourceUri backend used by terminal linkification.
Changes:
- Refactors terminal stack-frame matching to use a shared
parseJavaStackFramehelper. - Introduces an untitled-document
DocumentLinkProviderplus commands to analyze/navigate stack traces, with registration deferred until the Java language server reaches Standard mode. - Updates extension activation and command contributions to surface
Java: Analyze Stack Traceand activate on Java workspaces.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/terminalLinkProvider.ts | Reuses shared stack frame parsing for terminal linkification. |
| src/stackTraceLinkProvider.ts | Adds untitled-document linkification + commands for stack-trace navigation and optional scratch-doc creation. |
| src/stackFrameParser.ts | Introduces a shared Java stack frame parser used by both terminal and document providers. |
| src/extension.ts | Wires stack-trace link provider registration into extension activation. |
| package.json | Activates earlier on Java workspaces and contributes the new command + palette visibility gating. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Cap clipboard prefill content, clarify command registration readiness, and add regression coverage for shared stack frame parsing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6e50dc26-84c4-4532-a7d3-88f6fe016780
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
Encode command URI arguments as an array and validate navigation command inputs before resolving source locations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6e50dc26-84c4-4532-a7d3-88f6fe016780
Use local values for command argument narrowing and make the parser example reflect its required leading whitespace. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6e50dc26-84c4-4532-a7d3-88f6fe016780
Validate parsed line numbers centrally so all stack trace link surfaces reject non-positive and unsafe values. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6e50dc26-84c4-4532-a7d3-88f6fe016780
Defer clipboard parsing to the bounded document link provider and dispose the one-shot server mode listener after registration. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6e50dc26-84c4-4532-a7d3-88f6fe016780
Preserve complete clipboard content and bound document link scans by total characters and lines so saved log files can be handled safely. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6e50dc26-84c4-4532-a7d3-88f6fe016780
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
src/stackTraceLinkProvider.ts:162
analyzeStackTraceinserts the full clipboard text into an untitled document. Very large clipboards can create huge in-memory documents and can noticeably impact VS Code responsiveness even though link scanning is later bounded. Consider capping the inserted text to the same size budget used by the link provider (or prompting before opening a very large document).
const clipboardContent = await env.clipboard.readText();
const document = await workspace.openTextDocument({ language: "log", content: clipboardContent });
await window.showTextDocument(document);
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
src/stackTraceLinkProvider.ts:46
isStackFrameLinkArgsnarrowsargstoobject, but then accessesargs.stackTrace/args.methodName/args.lineNumberdirectly. In TypeScript,objectdoes not allow property access, so this is likely a compile-time error (or forces unsafe typing). Narrow to aRecord<string, unknown>(or use a type assertion) before reading properties.
function isStackFrameLinkArgs(args: unknown): args is IStackFrameLinkArgs {
if (typeof args !== "object" || args === null) {
return false;
}
const stackTrace = "stackTrace" in args ? args.stackTrace : undefined;
const methodName = "methodName" in args ? args.methodName : undefined;
const lineNumber = "lineNumber" in args ? args.lineNumber : undefined;
if (typeof stackTrace !== "string" || typeof methodName !== "string" || typeof lineNumber !== "number"
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
Closes #1654 (draft for design review — not ready to merge).
What & why
Developers frequently receive Java stack traces from log files, CI failures, bug reports, chat messages, and production logs. Eclipse ("Java Stack Trace Console") and IntelliJ ("Analyze Stack Trace") let users click frames from an external trace and jump to source without a running debug session.
VS Code's existing Java stack-trace linkifier only handles output that has already flowed through the integrated terminal. This PR adds the missing standalone text-document workflow.
User experience
.logfile and click Java stack frames directly.Java: Analyze Stack Traceto open an untitled document prefilled with the complete clipboard text.No active debug session is required.
Implementation
DocumentLinkProviderinsrc/stackTraceLinkProvider.tshandles untitled documents and.logfiles.activationEventsincludesworkspaceContains:**/*.java, so the extension activates when a Java workspace is opened.redhat.javareachesServerMode.STANDARD; the one-shot server-mode listener is disposed after registration.vscode.java.resolveSourceUribackend. No Java backend changes are required.src/stackFrameParser.tsis shared by the terminal and document link providers so both surfaces recognize the same frame syntax.Scope and safety
The document selector covers:
Java: Analyze Stack Trace..logfiles matching**/*.log, including external logs outside the workspace root while a Java workspace is active.The extension only scans documents the user opens; it does not search the filesystem. Other plaintext files remain excluded.
Each provider invocation:
Command-link arguments are validated before backend resolution, line numbers must be positive safe integers, and resolved source URIs are restricted to the expected
fileandjdtschemes.Demo
linkfy.mp4