Skip to content

Commit bc01e67

Browse files
Merge pull request #2 from soumyaprasadrana/dev
💡 Macro Multithread recording and playback
2 parents eb78f3b + 1a4c1ba commit bc01e67

14 files changed

Lines changed: 331 additions & 125 deletions

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ node_modules/
22
out
33
classes/
44
macros/
5-
vscode-java-debugx-*
5+
vscode-java-debugx-*.json
6+
vscode-java-debugx-*.vsix

README.md

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -16,96 +16,97 @@
1616
---
1717

1818

19-
## Overview
19+
## 🌟 Overview
2020

21-
**Java DebugX** is a Visual Studio Code extension aimed at improving Java debugging by offering advanced macro recording and playback features. It allows developers to record key debugging events such as step-in, step-out, and breakpoints in a macro JSON format. This feature enables users to capture complex debugging sessions and replay them later, saving time and eliminating the need to manually redo the debugging process.
21+
**Java DebugX** is a powerful Visual Studio Code extension designed to enhance your Java debugging experience with advanced macro recording and playback features. 📽️✨ With Java DebugX, you can record essential debugging events—like **step-in**, **step-out**, and **breakpoints**in a structured JSON format.
2222

23+
This feature enables you to capture intricate debugging sessions and replay them effortlessly, saving time and sparing you from manually redoing steps. ⏱️🔄 Perfect for complex Java applications, Java DebugX streamlines your workflow and boosts your productivity. ⚡
2324

2425
## Features
2526

26-
- **Macro Recording and Playback**: Record debugging sessions, including step-ins, step-outs, and breakpoints. Play back the recorded sessions at any time.
27+
- 🎥 **Macro Recording & Playback**: Effortlessly record your debugging sessions, capturing all **step-ins**, **step-outs**, and **breakpoints**. Rewind and replay these recorded sessions anytime for quick and efficient troubleshooting! ⏪⏯️
2728
**Recording**
2829
![JavaDebugXMacroRecording](/media/vscode-java-debugx-macro-recording.gif)
2930
**Playback**
3031
![JavaDebugXMacro](/media/vscode-java-debugx-play-macro.gif)
32+
**🧵 Enhanced Multi-Threaded Compatibility**
33+
Java DebugX is designed to work seamlessly with **multi-threaded debugging**! 🎉 Now, you can record and replay debugging sessions even in complex, multi-threaded applications. This enhancement captures step-in, step-over, and other critical debugging events across threads, allowing you to efficiently review and trace through complex scenarios without retracing steps manually. 🚀
34+
![JavaDebugXMacroMultiThread](/media/vscode-java-debugx-play-macro-play-multithread.gif)
3135

32-
- **Customizable Bridge Configurations**: Define custom bridge classes and methods to integrate additional debugging insights.
33-
- **Advanced Debug Insights**: View detailed, real-time debugging information in a dedicated Insights view.
36+
- 🔧 **Customizable Bridge Configurations**: Set up custom bridge classes and methods to bring extra insights into your debugging process, tailored to your needs. 🌉
37+
- 🕵️‍♂️ **Advanced Debug Insights**: Access in-depth, real-time debugging details in the specialized **Insights** view for more informed problem-solving. 📊
3438
![DebugInsight](/media/vscode-java-debugx-bridge.gif)
3539

36-
- **Search External Files**: Search and index external files during debugging to improve traceability.
37-
- **Customizable File Patterns**: Define which files to include when indexing external files.
40+
- 🔍 **Search External Files**: Seamlessly search and index external files during debugging to boost traceability and streamline your workflow. 📁
41+
- 🎛️ **Customizable File Patterns**: Tailor which files to include in indexing external files by defining custom file patterns for optimized debugging. 📝
3842

3943

4044

4145

42-
## Installation
46+
## 🚀 Installation
4347

4448
To install the **Java DebugX** extension in Visual Studio Code:
4549

4650
1. Open **Visual Studio Code**.
4751
2. Go to the **Extensions** view by clicking on the Extensions icon in the Activity Bar or pressing `Ctrl+Shift+X`.
48-
3. Search for **Java DebugX**.
49-
4. Click **Install**.
50-
51-
Here's the updated section with the Open VSX URL included:
52+
3. 🔍 Search for **Java DebugX**.
53+
4. Click **Install** to add it to your editor.
5254

5355
> Alternatively, you can install it directly from the [Marketplace](https://marketplace.visualstudio.com/items?itemName=soumyaprasadrana.vscode-java-debugx) or from [Open VSX](https://open-vsx.org/extension/soumyaprasadrana/vscode-java-debugx).
5456
55-
## Getting Started
56-
57-
Once installed, the extension is activated when a Java project is opened. You can then start using the extension to record, play, and analyze debugging sessions.
57+
## 🎉 Getting Started
5858

59-
### Key Features and Commands
59+
After installing **Java DebugX**, it activates automatically whenever you open a Java project. You can now dive right in and start using its powerful features to record, play back, and analyze your debugging sessions for a more efficient development workflow! 🛠️
6060

61-
- **Start Macro Recording**: Begin recording your debugging session. This will capture step-ins, step-outs, and breakpoints.
62-
- **Stop Macro Recording**: Stop recording and save the session data.
63-
![MacroRecActions](/media/vscode-java-debugx-macro-start-stop.gif)
64-
- **Play Macro Recording**: Re-execute the recorded session.
65-
- **Pause/Resume/Stop Macro Playback**: Pause,resume or stop the playback of your recorded debugging session.
66-
![MacroRecPlayActions](/media/vscode-java-debugx-play-macro-action-buttons.gif)
67-
- **Generate Sample Bridge Config**: Generate a sample configuration file to set up your custom bridge and define commands.
68-
- **Debug Insights**: View detailed insights from bridge configuration into your debugging session through a dedicated panel.
61+
### 🚀 Key Features and Commands
6962

70-
You can access these commands via the **Command Palette** (`Ctrl+Shift+P`), or find them in the **JavaDebugX** menu.
63+
- **🎬 Start Macro Recording**: Begin capturing your debugging session, including step-ins, step-outs, and breakpoints.
64+
- **⏹️ Stop Macro Recording**: End the recording and save the session data.
65+
![MacroRecActions](/media/vscode-java-debugx-macro-start-stop.gif)
66+
- **▶️ Play Macro Recording**: Re-execute the captured debugging session.
67+
- **⏸️/▶️/⏹️ Pause, Resume, or Stop Playback**: Control the playback of your recorded debugging session.
68+
![MacroRecPlayActions](/media/vscode-java-debugx-play-macro-action-buttons.gif)
69+
- **🛠️ Generate Sample Bridge Config**: Create a sample config file to define custom bridge commands and methods.
70+
- **🔍 Debug Insights**: Access detailed insights and bridge configurations in a dedicated panel for enriched debugging information.
7171

72+
These commands are accessible through the **Command Palette** (`Ctrl+Shift+P`). Happy debugging! 🎉
7273

73-
## Configuration
74+
## Configuration ⚙️
7475

7576
You can configure the extension by modifying the settings in your `settings.json`. The available settings are:
7677

77-
- **java.debugx.filePatterns**: Define file patterns to include when indexing external files (e.g., `*.java`, `*.js`, `*.xml`).
78-
- **java.debugx.externalFolder**: Set the path to an external folder that you want to index.
79-
- **java.debugx.macro.stepDelayInSeconds**: Configure the step delay during macro playback.
80-
- **java.debugx.bridgeConfigPath**: Set the absolute path to your custom bridge configuration file.
81-
82-
You can access and modify these settings in the **Settings** tab or directly in your `settings.json` file.
78+
- **java.debugx.filePatterns** 📂: Define file patterns to include when indexing external files (e.g., `*.java`, `*.js`, `*.xml`).
79+
- **java.debugx.externalFolder** 🗂️: Set the path to an external folder that you want to index.
80+
- **java.debugx.macro.stepDelayInSeconds** ⏱️: Configure the step delay during macro playback.
81+
- **java.debugx.bridgeConfigPath** 🔧: Set the absolute path to your custom bridge configuration file.
8382

84-
## Views and Menus
83+
You can access and modify these settings in the **Settings** tab ⚙️ or directly in your `settings.json` file.
8584

86-
- **Insights View**: A dedicated view to show real-time debugging insights.
87-
![DebugInsightView](/media/vscode-java-debugx-bridge-insights.gif)
85+
## Views and Menus 🖥️
8886

89-
- **Debug Toolbar**: Commands for controlling the macro recording and playback are available in the debug toolbar.
87+
- **Insights View** 📊: A dedicated view to show real-time debugging insights.
88+
![DebugInsightView](/media/vscode-java-debugx-bridge-insights.gif)
9089

91-
## Example Usage
90+
- **Debug Toolbar** 🛠️: Commands for controlling the macro recording and playback are available in the debug toolbar.
9291

93-
### Generating a Sample Bridge Config
92+
## Example Usage 💡
9493

95-
To generate a sample bridge configuration file:
94+
### Typical Scenario 🚀
9695

97-
1. Open the Command Palette (`Ctrl+Shift+P`).
98-
2. Search for and select **Generate Sample Bridge Config**.
96+
Here’s a typical scenario: You’re debugging a large Java application and find a potential root cause. But after stepping forward, you realize you need to repeat the process to verify something. In a real-life setting, this is where Java DebugX shines—you can record the session once, then replay it up to the exact point you need to examine again.
9997

100-
This will generate a new bridge configuration file in your workspace, which you can modify to create your custom bridge logic.
98+
**Java DebugX** even includes enhanced diagnostics to help when your macro takes a wrong path. If your playback reaches a point that differs from the expected line (like reaching an unexpected catch block or exception), DebugX will try to gather diagnostics and log them to a file, giving you a better understanding of potential issues. 📂🛠️
10199

100+
### Generating a Sample Bridge Config ⚙️
102101

102+
To generate a sample bridge configuration file:
103103

104-
## Limitation
104+
1. Open the Command Palette (`Ctrl+Shift+P`) 🔍.
105+
2. Search for and select **Generate Sample Bridge Config** 📝.
105106

106-
The macro recording feature is well-tested when your debug session interacts with only a single thread. However, if you are debugging multiple threads simultaneously, the events will be recorded but playback might not work as expected. We are actively working on improving support for multi-threaded debugging sessions.
107+
This will generate a new bridge configuration file in your workspace, which you can modify to create your custom bridge logic. 🔧
107108

108-
## Development
109+
## Development 🛠️
109110

110111
If you'd like to contribute or develop the extension locally, follow these steps:
111112

@@ -117,19 +118,18 @@ If you'd like to contribute or develop the extension locally, follow these steps
117118
```bash
118119
npm install
119120
```
120-
3. Launch the extension in VS Code with from debug view
121+
3. Launch the extension in VS Code from the debug view ▶️
121122

122-
## License
123+
## License 📜
123124

124125
This project is licensed under the [SEE LICENSE IN LICENSE](LICENSE).
125126

126-
## Author
127+
## Author ✍️
127128

128129
**Soumya Prasad Rana**
129-
Email: soumyaprasad.rana@gmail.com
130-
GitHub: [soumyaprasadrana](https://github.com/soumyaprasadrana)
130+
Email: soumyaprasad.rana@gmail.com 📧
131+
GitHub: [soumyaprasadrana](https://github.com/soumyaprasadrana) 🐙
131132

132-
## Support
133+
## Support 🆘
133134

134135
If you encounter any issues or need help, please visit the [issues page](https://github.com/soumyaprasadrana/vscode-java-debugx/issues) and open a new issue or check for existing discussions.
135-
2.93 MB
Loading
1.94 MB
Loading

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"name": "Soumya Prasad Rana",
77
"email": "soumyaprasad.rana@gmail.com"
88
},
9-
"version": "1.0.2",
9+
"version": "1.0.3",
1010
"publisher": "soumyaprasadrana",
1111
"icon": "vscode-java-debugx.png",
1212
"engines": {

src/debugSessionsTracker.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ export class DebugSessionsTracker implements vscode.DebugAdapterTracker {
5252
private currentFrame: any;
5353
private currentThread: any;
5454

55+
private debugRequestMap: Map<number, { request: any; response: any }> = new Map();
56+
57+
5558
// Singleton implementation
5659
private constructor(session: vscode.DebugSession) {
5760
this.setActiveSession(session);
@@ -186,13 +189,30 @@ export class DebugSessionsTracker implements vscode.DebugAdapterTracker {
186189

187190
onWillReceiveMessage(message: any) {
188191
//console.log("onWillReceiveMessage", message);
192+
if (message && message.type && message.type == 'request' && (message.command == 'threads' || message.command == 'evaluate' || message.command == 'variables')) return; //Performance ; We don't need these request for macro processing
193+
189194
this.debugSessionEventTracker.push({ event: "onWillReceiveMessage", eventMessage: message });
195+
if (message && message.type && message.type == 'request') {
196+
//Store the request into the map
197+
this.debugRequestMap.set(message.seq, { request: message, response: null })
198+
}
190199
}
191200

192201
onDidSendMessage?(message: any): void {
193202
//console.log("onDidSendMessage", message);
203+
if (message && message.type && message.type == 'response' && (message.command == 'threads' || message.command == 'evaluate' || message.command == 'variables')) return; //Performance ; We don't need these request for macro processing
204+
194205
this.debugSessionEventTracker.push({ event: "onDidSendMessage", eventMessage: message });
195206

207+
if (message && message.type && message.type == 'response') {
208+
let reqMap = this.debugRequestMap.get(message.request_seq);
209+
if (reqMap) {
210+
reqMap.response = message;
211+
this.debugRequestMap.set(message.request_seq, reqMap);
212+
}
213+
214+
}
215+
196216
if (message.event === 'stopped') {
197217
this.currentThread = message.body.threadId;
198218
} else if (message.command === 'stackTrace' && this.currentThread !== null) {
@@ -292,7 +312,7 @@ export class DebugSessionsTracker implements vscode.DebugAdapterTracker {
292312
lastStackFrame.line !== currentFrame.line ||
293313
lastStackFrame.method !== currentFrame.method) {
294314
// Extract the last relevant event for the step
295-
const lastEvent = this.getLastThreadOperationEvent(sessionData.events);
315+
const lastEvent = this.getLastThreadOperationEvent(sessionData.events, eventMessage);
296316

297317
if (lastStoppedEvent.body.reason == 'breakpoint' && lastEvent.event.command == 'continue') {
298318
const lastSetBreakPointEvent = this.getLastThreadBreakpointOperationEvent(sessionData.events);
@@ -364,11 +384,32 @@ export class DebugSessionsTracker implements vscode.DebugAdapterTracker {
364384
return sessionData;
365385
}
366386

367-
private getLastThreadOperationEvent(events: { event: any; parsedMessage: string }[]): any {
387+
private getLastThreadOperationEvent(events: { event: any; parsedMessage: string }[], currentEvent: any): any {
368388
for (let i = events.length - 1; i >= 0; i--) {
369389
const event = events[i];
370390
// Check the parsedMessage for relevant thread operations
371391
if (event.parsedMessage.includes('Step command issued:')) {
392+
if (currentEvent.request_seq) {
393+
const reqResMap = this.debugRequestMap.get(currentEvent.request_seq); // retrieve the reqResMap to validate the thread ID of the current event
394+
if (reqResMap?.request && reqResMap?.request.arguments && reqResMap?.request.arguments.threadId) {
395+
const currentEventThreadId = reqResMap?.request.arguments.threadId;
396+
const prevThreadOpEventThreadId = event?.event.arguments.threadId;
397+
if (currentEventThreadId != prevThreadOpEventThreadId) {
398+
// Mock event to prevent the current event from playing prev event while macro playback
399+
return {
400+
event: {
401+
command: "multithread-stopped",
402+
arguments: {
403+
threadId: currentEventThreadId
404+
},
405+
type: "request",
406+
seq: 191
407+
}, parsedMessage: 'Thread stopped'
408+
} // Thread doesn't match seems the current event is paused by a breakpoint and user's debug session is multithreaded
409+
}
410+
}
411+
412+
}
372413
return event; // Return the last relevant thread operation event
373414
}
374415
}

src/handleGetDebugInsights.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,39 @@ import { ContextProvider } from './vscodeContextProvider';
1717
export class DebugInfoStore {
1818
private activeThread: vscode.DebugThread | null = null;
1919
private activeStackFrame: vscode.DebugStackFrame | null = null;
20+
private isMultiThreadedSession: boolean = false;
21+
private activeThreadIdForMultiThreadedSession: any = null;
22+
private hasThreadChangedBetweenFrames: boolean = false;
23+
24+
public setMultiThreadedSession() {
25+
this.isMultiThreadedSession = true;
26+
}
27+
28+
public setActiveThreadForMultiThreadSession(threadId: any) {
29+
this.activeThreadIdForMultiThreadedSession = threadId;
30+
}
31+
32+
public setHasThreadChangedBetweenFrames(status: boolean) {
33+
this.hasThreadChangedBetweenFrames = status;
34+
}
35+
36+
public getHasThreadChangedBetweenFrames(): boolean {
37+
return this.hasThreadChangedBetweenFrames;
38+
}
39+
40+
public isMultiThreaded(): boolean {
41+
return this.isMultiThreadedSession;
42+
}
43+
44+
public resetMultiThreadVars() {
45+
this.isMultiThreadedSession = false;
46+
this.hasThreadChangedBetweenFrames = false;
47+
this.activeThreadIdForMultiThreadedSession = null;
48+
}
49+
50+
public getThreadIdForMultiThreadedSession() {
51+
return this.activeThreadIdForMultiThreadedSession;
52+
}
2053

2154
// Store the active thread and frame information
2255
public updateActiveDebugInfo(thread: vscode.DebugThread | null, stackFrame: vscode.DebugStackFrame | null) {

0 commit comments

Comments
 (0)