Skip to content

Instantly share code, notes, and snippets.

@julio73
Last active March 9, 2020 17:54
Show Gist options
  • Save julio73/ec87b0cfbf371d8e67a5cd0941d23fbc to your computer and use it in GitHub Desktop.
Save julio73/ec87b0cfbf371d8e67a5cd0941d23fbc to your computer and use it in GitHub Desktop.
A case for a faster debugging workflow in VS Code for SFDX projects

A solution for a faster debugging workflow in VS Code for SFDX projects

My problem:

In most cases, I launch an Apex Replay Debugger session to review the last generated log file on my Salesforce sandboxes. However, retrieving the latest log from Salesforce to VS Code for debugging requires:

  • Triggering the command to retrieve the debug logs (SFDX: Get Apex Debug Logs...)
  • Waiting and watching out for a popup that lists all the recent debug logs
  • Selecting the first (or desired) debug log for download, note: the popup might easily dismiss itself if doing anything else at this stage
  • Finally, launching the replay debugger for the downloaded log (SFDX: Launch Apex Replay Debugger with Current File)

The above steps take too much of my attention and are not fun to keep track on a spotty internet connection.

My solution:

I believe all the steps described earlier can be and should be relegated to VS Code background tasks.

I have edited the tasks.json and launch.json files in my project .vscode/ folder. I have added an additional debugger configuration: Launch Apex Replay Debugger with latest file that can retrieve the latest log file (if any) generated on the sandbox for debugging. On launch, the debugger will offer the option to retrieve the latest debug log or record some logs first before debugging.

On the first-run, I retrieve the latest log file on the sandbox to generate the local log file latest.log. This is the local file that is then used in all the actions below.

On subsequent runs, I can choose to simply run with the stale local file or update the file by overwriting its content with the content of the most recent log on the sandbox.

Alternatively, I can choose to tail the logs, then do some actions that would generate new logs, and finally stop the recording (ctrl+c) to save the logs to begin the debug session right away.

The default pre-task option is "" which means run the debugger with whatever content is in the log file.

My benefits:

First, while the logs are being tailed, I can focus on updating my breakpoints or checkpoints, allowing me to stay focused on my code instead of the log retrieval process.

Second, to reach my breakpoints faster, I sometimes set "stopOnEntry": false on the debug configuration. As a result, the logs are processed as soon as they are retrieved and only stop if they reach a breakpoint. This approach removes the guess work on whether or not my actions made use of the code I tracked. Here none of my attention is used unless necessary i.e. a breakpoint is reached.

Lastly, I no longer spend my time comparing which of the logs I retrieved contains the necessary log lines. With the tail log task, all the recents logs get combined into the same file while recording. The log file has a fixed name and removes the need to keep downloading, scanning and/or comparing logs.

Disclaimer:

I didn't test any of this on Windows ¯\_(ツ)_/¯. However, I tried maintaining the shell commands general enough for the default setup.

I am not well versed in the logic of VS Code task's problem matchers. The problem matcher specified in the tail task is purely to avoid VS Code complaining about halting with ... exit code: 130 upon a ctrl+c press. The specified "pattern" is the default one provided from VS Code. and the "background" was my attempt at recognizing a succesful tail retrieval of valid logs necessary for Apex Replay Debugging. I welcome all feedback on the entire approach as well as any tips to improve this.

"There must be a better way!" - Raymond H.

{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Apex Replay Debugger",
"type": "apex-replay",
"request": "launch",
"logFile": "${command:AskForLogFileName}",
"stopOnEntry": true,
"trace": true
},
{
"name": "Launch Apex Replay Debugger on latest file",
"type": "apex-replay",
"request": "launch",
"logFile": "${workspaceFolder}/.sfdx/tools/debug/logs/latest.log",
"stopOnEntry": true,
"trace": true,
"preLaunchTask": "${input:latestLogFileActions}"
}
],
"inputs": [
{
"id": "latestLogFileActions",
"type": "pickString",
"description": "Pre-task to run.",
"default": "",
"options": [
"",
"apex: retrieve the last generated log",
"apex: record new logs and save to file"
]
}
]
}
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "apex: retrieve the last generated log",
"type": "shell",
"command": "echo 'Retrieving the latest log...' && (sfdx force:apex:log:get --loglevel fatal | tee ${workspaceFolder}/.sfdx/tools/debug/logs/latest.log) && echo 'Retrieval complete.'",
"windows": {
"command": "echo 'Retrieving the latest log...' && (sfdx force:apex:log:get --loglevel fatal | tee ${workspaceFolder}\\.sfdx\\tools\\debug\\logs\\latest.log) && echo 'Retrieval complete.'"
},
"detail": "Retrieve and save the content of the last generated log.",
"problemMatcher": [],
"presentation": {
"showReuseMessage": false,
"group": "apex"
},
"runOptions": {
"reevaluateOnRerun": false
}
},
{
"label": "apex: record new logs and save to file",
"type": "shell",
"command": "echo 'Now recording logs...' && (sfdx force:apex:log:tail --skiptraceflag --loglevel fatal | tee ${workspaceFolder}/.sfdx/tools/debug/logs/latest.log); echo '\nRecording complete and saved to file.'",
"windows": {
"command": "echo 'Now recording logs...' && (sfdx force:apex:log:tail --skiptraceflag --loglevel fatal | tee ${workspaceFolder}\\.sfdx\\tools\\debug\\logs\\latest.log); echo '\nRecording complete and saved to file.'"
},
"detail": "Record and save new logs generated by the current user.",
"problemMatcher": {
"source": "tailing latest logs from sandbox",
"pattern":[
{
"regexp": "^([^\\\\s].*)\\\\((\\\\d+,\\\\d+)\\\\):\\\\s*(.*)$",
"file": 1,
"location": 2,
"message": 3
}
],
"background": {
"activeOnStart": true,
"beginsPattern": "(APEX_CODE,FINEST).*(VISUALFORCE,FINER)",
"endsPattern": "\\n$(?![\\r\\n])"
}
},
"presentation": {
"showReuseMessage": false,
"group": "apex",
"clear": true
},
"runOptions": {
"reevaluateOnRerun": false
},
"promptOnClose": true
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment