Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debugging functionality #250

Open
nkskaare opened this issue Oct 1, 2024 · 9 comments
Open

Debugging functionality #250

nkskaare opened this issue Oct 1, 2024 · 9 comments

Comments

@nkskaare
Copy link

nkskaare commented Oct 1, 2024

Hi!

I have been able to run the debugger from https://github.com/forcedotcom/salesforcedx-vscode as a server and connect to it using the nvim-dap. My implementation still has some work to do, but I am getting close, and it would be very cool to implement it into this plugin. My current nvim-dap configuration is the following. I am still struggling to dynamically pass in a logfile which i want to debug. Ideally I would like to run a test and then have a debug session it afterwards, not having to manually select which logfile i want to run (which is how it is implemented in vscode today).

return {
  "mfussenegger/nvim-dap",
  lazy = true,
  config = function()
    local dap = require("dap")

    local function find_apex_ls()
      for _, client in pairs(vim.lsp.get_clients({ name = "apex_ls" })) do
        return client
      end
    end

    local function get_line_breakpoint_info()
      -- Find the apexls client
      local apex_client = find_apex_ls()

      if not apex_client then
        print("Apex Language Server is not available.")
        return
      end

      local res = nil
      local done = false

      -- Send the request to the Apex Language Server
      apex_client.request("debugger/lineBreakpoints", {}, function(err, result, ctx, config)
        if err then
          print("Error:", err)
        end

        print("Breakpoint info receieved", vim.inspect(result))
        done = true
        res = result
      end)

      -- Block until the LSP request is done or 5000ms (5 seconds) have passed
      vim.wait(5000, function()
        return done
      end, 100) -- Check every 100ms

      return res
    end

    local lineBreakpointInfo = get_line_breakpoint_info()
    if lineBreakpointInfo then
      print("Line breakpoint info received")
    end

    dap.set_log_level("DEBUG")

   -- For some reason I had to configure both for "apex-replay" and "apex"

    dap.adapters["apex-replay"] = {
      type = "server",
      host = "127.0.0.1",
      port = 4712, -- Make sure this matches your debug server port
    }

    -- Map VS Code launch.json settings to nvim-dap configurations
    dap.configurations["apex-replay"] = {
      {
        name = "Launch Apex Replay Debugger",
        type = "apex-replay", -- Matches the adapter type defined above
        request = "launch",
        logFile = "/MySfProject/.sfdx/tools/debug/logs/07LKF000007iKw62AE.log", -- Prompt for log file, similar to VS Code's AskForLogFileName
        stopOnEntry = true, -- Equivalent to stopOnEntry in VS Code
        trace = true, -- Equivalent to trace: true in VS Code
        lineBreakpointInfo = lineBreakpointInfo,
        projectPath = "/MySfProject/src/",
      },
    }

    dap.adapters.apex = {
      type = "server",
      host = "127.0.0.1",
      port = 4712, -- Make sure this matches your debug server port
    }

    -- Map VS Code launch.json settings to nvim-dap configurations
    dap.configurations.apex = {
      {
        name = "Launch Apex Replay Debugger",
        type = "apex-replay", -- Matches the adapter type defined above
        request = "launch",
        logFile = "/MySfProject/.sfdx/tools/debug/logs/07LKF000007iKw62AE.log", -- Prompt for log file, similar to VS Code's AskForLogFileName
        stopOnEntry = true, -- Equivalent to stopOnEntry in VS Code
        trace = true, -- Equivalent to trace: true in VS Code
        lineBreakpointInfo = lineBreakpointInfo,
        projectPath = "/MySfProject/src/",
      },
    }

    -- Optional: Set up DAP UI for better visualization
    -- require("dapui").setup()
  end,
}

@xixiaofinland
Copy link
Owner

xixiaofinland commented Oct 1, 2024

Hi @nkskaare
What you've done is a really interesting topic. Thank you for sharing it here!

@FedeAbella
What are your thoughts on this? You recently worked on the log feature, and the combination of apex-replay with DAP is a fairly handy feature worth exploring.

Hope we can sort this out in collaboration ❤️!

@nkskaare
Copy link
Author

nkskaare commented Oct 1, 2024

Happy to collaborate on this! What I've done so far is only a POC and I was able to run a debugging session in nvim. However, I'm quite new to nvim and not very skilled in lua, so that's why I thought it would be better handed over to someone who can implement this properly. The details for running the debug server could be found in launch.json of the vscode-extension repo I linked above

{
  "name": "Launch Replay Debugger adapter",
  "type": "node",
  "request": "launch",
  "cwd": "${workspaceFolder}",
  "program": "${workspaceFolder}/packages/salesforcedx-apex-replay-debugger/out/src/adapter/apexReplayDebug.js",
  "args": ["--server=4712"],
  "sourceMaps": true,
  "smartStep": true,
  "outFiles": ["${workspaceFolder}/packages/*/out/src/**/*.js"],
  "sourceMapPathOverrides": {
    "webpack:///salesforcedx-utils-vscode/./*": "${workspaceFolder}/packages/salesforcedx-utils-vscode/*",
    "webpack:///salesforcedx-sobjects-faux-generator/./*": "${workspaceFolder}/packages/salesforcedx-sobjects-faux-generator/*",
    "webpack:///*": "*"
  },
  "preLaunchTask": "Compile"
},

The project needs to be compiled (typescript) and then run the apexReplayDebug.js --server 4712.

@FedeAbella
Copy link
Collaborator

Ooooh, I love this! Great work @nkskaare. I've had this going around my head for a while now and didn't know how to tackle it.

To be honest, I haven't used nvim-dap before, and even though I've used the Apex Replay Debugger in VSCode, I wouldn't say I know it too well. BUT, I'd love to see if we can tackle this. Without going deep into the shared code (it's a busy day today), I think there's at least a few points we should keep in mind:

  1. How to set up what nvim-dap needs without possibly messing up a user's preestablished config (we could start off by just telling the user how to do it, until we find how to do it from our own setup, if at all possible)
  2. How to install and set up the server from the plugin (again, we could start us off by having the user do it, then upgrade to do it ourselves for conveniency)
  3. While I get wanting to default to the last log, I think we'd want to keep some kind of functionality that would let the user debug a chosen log. Maybe you're in a shared sandbox where other people create lots of logs, maybe the functionality you want to debug creates async processes, maybe you just want to check that previous time it worked well. So, maybe have 2 methods? Something like debug_last_log and debug_log? Just a thought

Let me see what I can put together from what nkskaare shared, when I've got some time, and we can make it from there. I could probably use your help with knowing more about this already @nkskaare, if I run into some blockers.

@xixiaofinland
Copy link
Owner

Great! Let's keep this thread open. Feel free to @me if any help from me is needed.
As you know, my focus is somewhere else at the moment @FedeAbella :)

@nkskaare
Copy link
Author

nkskaare commented Oct 2, 2024

Great! I have used the debugger in VSCode quite actively, and spent some time trying to unwrap what happens under the hood when setting up this POC, so happy to share my insight. I agree very much with the things listed here.

My current code is quite a naive approach, but it shows the core of it. The debugger requires some additional details on breakpoint lines from the language server, hence the "debugger/lineBreakpoints" request to the language server.

One problem with my current config/code as you can probably figure is that it runs when the nvim-dap plugin is loaded (using lazy.nvim), so this code should probably be triggered by a command implemented in the sf plugin. With the current config I have to restart nvim each time I want to run a debugging session. I have also read somewhere that nvim-dap can read launch.json files, so this could also be a feature to explore further.

As you suggest i think in a first iteration the user should setup the server on their own. As I was fiddling around with this I found out that it was quite simple to set up (compile project and run node apexReplayDebug.js --server 4712).

Furthermore some sf cli commands must be run to actually start logging debug logs and create DebugLevel and TraceFlag records in Salesforce. In VSCode these are triggered by running SFDX: Turn On Apex Debug Log for Replay Debugger from command palette, and list the following commands in the output.

$ sf data:query --query SELECT id, logtype, startdate, expirationdate, debuglevelid, debuglevel.apexcode, debuglevel.visualforce FROM TraceFlag WHERE logtype='DEVELOPER_LOG' AND TracedEntityId='005KO000001AS22YAG' --use-tooling-api --json

$ sf data:create:record --sobject DebugLevel --values developername=ReplayDebuggerLevels1727860853933 MasterLabel=ReplayDebuggerLevels1727860853933 apexcode=FINEST visualforce=FINER --use-tooling-api --json

$ sf data:create:record --sobject TraceFlag --values tracedentityid='005KO000001AS22YAG' logtype=developer_log debuglevelid=7dlKO000000Cd6CYAS StartDate='' ExpirationDate='Wed, 02 Oct 2024 09:50:55 GMT --use-tooling-api --json

TracedEntityId is the user id.

By default this sets the expiration for the TraceFlag 30 minutes ahead in time (quite an annoyance sometimes, could be nice with a longer/custom expiration time)

Getting the logs from salesforce can also be acheived with the cli

sf apex get log

I think it's a very good suggestion to have functionality to debug a chosen log. Two methods like debug_last_log and debug_log is just great! My "dream" of running a test and debugging it in one command is probably a bit further down the line and would probably chain more basic commands like this.

@FedeAbella
Copy link
Collaborator

Hey @nkskaare! Sorry, it's been a hectic week, I'm only just now able to start looking into this. Unfortunately, I don't know much node and TS, so I'm running into blockers early on with just trying to get the debugging server up and running. Could you help me out by providing some steps to compile the project and getting the server running?

Thanks!

@nkskaare
Copy link
Author

Sure! Let me see what i can do! I'll try to make a small step-by-step guide.

@nkskaare
Copy link
Author

nkskaare commented Oct 19, 2024

Sorry for the late response, hectic week on my side as well!

First, clone the salesforce-vscode repo
$ git clone https://github.com/forcedotcom/salesforcedx-vscode

Ensure you have npm and typescript installed. Typescript can be installed using npm
$ npm install typescript --global
$ tsc --version

at the project root, run
$ npm install
$ tsc --build

Then you should be able to run the adapter
$ node packages/salesforcedx-apex-replay-debugger/out/src/adapter/apexReplayDebug.js --server=4712

You should see the following message
waiting for debug protocol on port 4712

@FedeAbella
Copy link
Collaborator

Sounds straightforward enough. Thanks! I'll let you know when I've made some progress on this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants