Skip to Content
Technical Articles
Author's profile photo Arley Triana Morin

Set Up Remote Debugging to Diagnose CAP Applications (Node.js Stack) at Runtime on SAP BTP, Cloud Foundry Environment

Introduction

 

In this blog post, you learn how to set up remote debugging for a deployed CAP application instance running on SAP BTP, Cloud Foundry environment.

As a developer, this is one of the go methods when your application is misbehaving, and you can’t troubleshoot just by analyzing the logs or/and you can’t reproduce runtime errors on your development environment (local machine).

With remote debugging, you can use your local development environment to inspect and interact with the application to diagnose problems efficiently.

Disclaimer: It isn’t advisable to enable remote debugging for an application running on production.

The major topics that are covered include:

  • Authenticate to Cloud Foundry with the CLI
  • Connect to a Cloud Foundry application instance using the Secure Shell protocol (SSH)
  • Enable the Node.js inspector for remote debugging on a running application instance
  • Enable port forwarding to Cloud Foundry
  • Attach a Node.js debugger to a process running on a Cloud Foundry application instance

 

Step 1: Install and Verify the Cloud Foundry Command Line Interface (CLI) Installation

 

To install the Cloud Foundry CLI, follow the official guide.

To verify the installation, open a new command prompt session and run:

╰─$ cf -v

If your installation was successful, the Cloud Foundry CLI version is displayed to standard output.

cf version 7.2.0+be4a5ce2b.2020-12-10

 

Step 2: Log In to the Cloud Foundry Instance with the CLI and SAP Single Sign-On

 

To log in to the Cloud Foundry, the cf login command is used.

cf login [-a API_URL] [-o ORG] [-s SPACE] [--sso]

Where:

  • API-URL is your API endpoint (for example, https://api.cf.eu20.hana.ondemand.com).
  • ORG is the org name where your application is deployed. Orgs map to business units have quota plans and unique roles.
  • SPACE is the space in the organization where your application is deployed. Spaces map to teams or products, hold applications and have unique roles.
  • --sso Prompt for a one-time passcode to log in. SAP Single Sign-On is the safest and most recommended way to log in.

The org name, API endpoint, and space information can be found in the SAP BTP Cockpit under HomeRegionsGlobal AccountsSubaccounts.

SAP BTP Cockpit Overview Screen

SAP BTP Cockpit Overview

 

Sample usage of the cf login command:

╰─$ cf login -a https://api.cf.eu20.hana.ondemand.com -o myorg -s myspace --sso
API endpoint: https://api.cf.eu20.hana.ondemand.com

Temporary Authentication Code ( Get one at https://login.cf.eu20.hana.ondemand.com/passcode ):

After running cf login with the --sso option, the Cloud Foundry CLI prompts for a one-time passcode to log in. Open a browser window, go to the URL https://login.cf.eu20.hana.ondemand.com/passcode , authenticate →

SAP BTP SSO

SAP BTP SAP Single Sign-On

 

SAP BTP Temporary Authentication Code

SAP BTP Temporary Authentication Code

 

, copy the one-time passcode, go back to the console and paste it into the prompt. Once authenticated, details of the targeted org and space are provided.

Temporary Authentication Code ( Get one at https://login.cf.eu20.hana.ondemand.com/passcode ):
Authenticating...
OK


Targeted org myorg.

Targeted space myspace.

API endpoint:   https://api.cf.eu20.hana.ondemand.com
API version:    3.99.0
user:           myemail@sap.com
org:            myorg
space:          myspace

Note that Cloud Foundry uses a role-based access control system to grant permissions to members, so make sure you’ve got the appropriate role permissions assigned. For example, by being an org auditor.

Step 3: Connect to a Cloud Foundry Application Instance Using SSH

 

Cloud Foundry allows you to SSH to application instances unless an org/space manager has prohibited this access. For more detailed information, you can refer to Enable and Disable SSH Access.

The cf ssh-enabled command checks whether an application is accessible via SSH:

╰─$ cf ssh-enabled myapp
ssh support is enabled for app 'myapp'.

If the app isn’t accessible via SSH, it can be enabled with the command cf enable-ssh.

╰─$ cf enable-ssh myapp
Enabling ssh support for app myapp as youremail@sap.com...
...
OK

You must restart your app after enabling SSH access. To restart your app, run the following command:

╰─$ cf restart myapp

Note that if a space manager disabled the access at the space level, all the applications that are part of this space would inherit the access level, and you as a developer won’t be able to SSH to an individual application even if you enabled SSH access at the application level.

If SSH access is allowed at the deployment, space, and application level, you can run the cf ssh myapp command to start an interactive SSH session with the VM hosting the application.

╰─$ cf ssh myapp
vcap@afa9bea3-b619-6476-5e97-1328:~$

 

Step 4: Enable the Node.js Inspector for Remote Debugging on a Running Application Instance

 

To enable debug mode for a running Node.js process, you need to know its unique process ID (PID). On Linux and Unix-like environments, the ps command gives you the information required.

vcap@afa9bea3-b619-6476-5e97-1328:~$ ps aux

USER    PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
vcap    151  0.0  0.1 687580 118376 ?       Sl   May28   0:05 node /home/vcap/deps/0/bin/npx cds run
...

Once the PID of the Node.js process running the application is known, you can use the kill command to send a debugging signal to it. The Node.js runtime activates the inspector protocol when it receives a usr1 signal. The inspector protocol is more or less a debugging protocol that allows tools to instrument, inspect, debug, and profile.

vcap@afa9bea3-b619-6476-5e97-1328:~$ kill -usr1 151

After sending this signal to the Node.js process, inspect the application logs, you see that a debugger is listening on ws://127.0.0.1:9229/48d7a94b-acb8-4d43-9932-95b781ee932d, this means that the Node.js process is switched into debug mode and start listening for debugging request on a WebSocket server at host and port 127.0.0.1:9229.SAP BTP Cockpit Application Logs

SAP BTP Cockpit Application Logs

 

Step 5: Enable Port Forwarding to Cloud Foundry

 

With port forwarding or port mapping, you can redirect TCP requests from your development machine to an application instance running on a VM.
In Cloud Foundry, port forwarding works by creating a listening TCP port on your local machine that maps to a TCP port on the VM via a secure SSH channel.

When using the cf ssh command,

the -L flag enables local port forwarding, binding an output port on your machine to an input port on the application VM. Pass in a local port and your application VM port and port number, all colon-delimited. You can prepend your local network interface or use the default localhost.

Enables local port forwarding

$ cf ssh MY-APP -L [LOCAL-NETWORK-INTERFACE:]LOCAL-PORT:REMOTE-HOST-NAME:REMOTE-HOST-PORT

Port forwarding sample usage:

cf ssh -N -L 9229:127.0.0.1:9229 myapp

This starts an SSH tunnel session where a connection to port 9229 on your development environment is forwarded to myapp instance on port 9229.

You can now attach a debugger such as Visual Studio Code or Chrome DevTools to localhost:9229. With this setup, you should be able to debug your application instance running on SAP BTP, Cloud Foundry environment, as if the Node.js application was running locally.

 

Step 6: Attach a Node.js Debugger to a Process Running on a Cloud Foundry Application Instance

 

Node.js debuggers typically support attaching to an already running program in debug mode. In VS Code and Chrome DevTools, there’s a built-in “Attach to Node Process” debugging model.

 

Attach VS Code Debugger

 

Add the following debug configuration to your launch.json file.

{
    "name": "Attach to a Cloud Foundry Instance on Port 9229",
    "port": 9229,
    "request": "attach",
    "type": "node",
    "localRoot": "${workspaceFolder}",
    "remoteRoot": "/home/vcap/app"
}

For example:

VS Code Debug Configuration

VS Code Debug Configuration

For detailed information on how to add a new debug configuration, refer to Add a new configuration.
Then on the sidebar, click on Run and Debug.

Then click on Start Debugging.

Open the Debug Console.

VS Code Debugger Console, Loaded Scripts ..

VS Code Debugger Console, Loaded Scripts …

At this point, if you followed the previous steps, you should be able to interact with the REPL, source code, and set breakpoints.

 

Attach Chrome DevTools

 

Open the Chrome browser or any Chromium-based browser and enter chrome://inspect in the address bar. Microsoft Edge also uses the same V8 JavaScript engine and can thus use the same debugger.

 

Chrome Browser Window

Chrome Browser Window

 

After navigating to the URL, you’ll see the following page:

Chrome Browser Window (Inspect Devices Screen)

Chrome Browser Window (Inspect Devices)

Under the Devices, click the Open dedicated DevTools for Node link, and a new window pops up for debugging a node session:

Chrome DevTools Node.js Debugger

Chrome DevTools Node.js Debugger

 

Chrome Debugger Console Panel

Chrome Debugger Console Panel

At this point, if you followed the previous steps, we’re now able to debug, interact with the REPL, source code, and set breakpoints.

Chrome Debugger Sources Panel

Chrome Debugger Sources Panel

Conclusions

 

Following the steps outlined in this blog post, you can set up remote debugging for CAP Applications (Node.js Stack) at runtime on SAP BTP and Cloud Foundry Environment. This will allow you to diagnose in real time and troubleshoot any issues that may arise in your applications. This approach will help you quickly identify the source of the problem and help you resolve it. Remote debugging provides a way to pinpoint the issue’s exact location and can help developers effectively fix it.

CLOUD FOUNDRY, the CLOUD FOUNDRY logo, and other CLOUD FOUNDRY marks used in this block post are trademarks of the CloudFoundry.org Foundation in the United States and other countries.

Assigned Tags

      23 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo David Kunz
      David Kunz

      Hey Arley Triana Morin,

      Thanks a lot for sharing, this is borderline magic!

      It even works with Neovim (using nvim-dap), so no more console.log on remote systems for me.

      Best regards,
      David

      Author's profile photo Shadab Alam
      Shadab Alam

      I miss the days of the good old /H    🙁

      Author's profile photo Jason Muzzy
      Jason Muzzy

      Hi Arley Triana Morin, thanks for sharing this!  When I try to ssh to my app I get the following error message: "Error opening SSH connection: You are not authorized to perform the requested action."  Any ideas?  I logged in with the --sso option, have the Space Manager (and Space Developer) roles assigned, verified SSH is enabled in the space, and enabled it for the app, so I'm at a loss.  Thanks for any help!

      Author's profile photo Arley Triana Morin
      Arley Triana Morin
      Blog Post Author

      Hi Jason,

      You are welcome. Have you tried to restart the app?

      > Note that if a space manager disabled the access at the space level, all the applications that are part of this space would inherit the access level, and you as a developer won’t be able to SSH to an individual application even if you enabled SSH access at the application level.

      Kind regards,
      Arley

      Author's profile photo Jason Muzzy
      Jason Muzzy

      Restarting the app worked!  Thank you so much for the suggestion!

      Author's profile photo James Tarver
      James Tarver

      Hi Arley,

      Nicely done! One point: the specification"${workspacefolder}" for the localRoot didn't work for me (macOS Monterey). I had to capitalize the F, so my complete entry in the launch.json looks like

      {
      "name": "Attach to a Cloud Foundry Instance on Port 9229",
      "port": 9229,
      "request": "attach",
      "type": "node",
      "localRoot": "${workspaceFolder}",
      "remoteRoot": "/home/vcap/app"
      }

      Author's profile photo Arley Triana Morin
      Arley Triana Morin
      Blog Post Author

      Hi James,

      I double-checked on that, and indeed, the variable substitution is as follows:

      ${workspaceFolder} - the path of the folder opened in VS Code
      https://code.visualstudio.com/docs/editor/variables-reference

      I corrected it.

      Thanks for pointing this out.

      Author's profile photo Leon Chen
      Leon Chen

      Hi Arley,

      Thanks a lot for sharing! This is a great article! I entered the URL "localhost:9229" in chrome, but get the error "WebSockets request was expected", do you know how to resolve this issue? Thanks.

      Author's profile photo Gregor Wolf
      Gregor Wolf

      As described in the blog post please try the URL chrome://inspect

      Author's profile photo Leon Chen
      Leon Chen

      Hi Gregor,

      Thanks for the response. I'm using VSCODE. It worked, thanks.

      Author's profile photo Mike B.
      Mike B.

      Arley Triana Morin, thanks for sharing the detailed manual.

      I am stuck at the «Step 3: Connect to a Cloud Foundry Application Instance Using SSH»:

      cf ssh-enabled myapp

      where myapp is a name of the wanted app, I got from cf html5-info, but I get:

      App 'myapp-html5-srv' not found.
      FAILED.

      How can I debug a server-side of the app from SAP BAS, running on SAP BTP?

      Author's profile photo Gregor Wolf
      Gregor Wolf

      Please avoid cross-posting and check the answer that I've given at Debugging server-side running on SAP BTP using SAP BAS

      Author's profile photo Mike B.
      Mike B.

      Arley Triana Morin, a question regarding the step «Step 4: Enable the Node.js Inspector for Remote Debugging on a Running Application Instance», I execute ps aux and get a list of running processes:

      root           1  0.0  0.0   1044     4 ?        Ss   16:16   0:00 /tmp/garden-init
      vcap           8  0.1  0.0 739588 46776 ?        Ssl  16:16   0:00 npm
      vcap           9  0.0  0.0 716040 10344 ?        Rsl  16:16   0:00 /tmp/lifecycle/diego-sshd --allowedKeyExchanges= --address=0.0.0.0:2222 --allowUnauthenticatedClients=false --inh
      root          75  0.0  0.0   4632   860 ?        Ss   16:16   0:00 sh -c trap 'kill -9 0' TERM; /etc/cf-assets/envoy/envoy -c /etc/cf-assets/envoy_config/envoy.yaml --drain-time-s 
      root         106  1.5  0.0 3284028 55696 ?       Sl   16:16   0:02 /etc/cf-assets/envoy/envoy -c /etc/cf-assets/envoy_config/envoy.yaml --drain-time-s 900 --log-level critical
      vcap         253  0.0  0.0   4644   804 ?        S    16:16   0:00 sh -c node node_modules/@sap/approuter/approuter.js
      vcap         254  0.5  0.0 854028 77320 ?        Sl   16:16   0:00 node node_modules/@sap/approuter/approuter.js
      root         265  0.0  0.0 706256  4896 ?        Ssl  16:16   0:00 /etc/cf-assets/healthcheck/healthcheck -port=8080 -timeout=1000ms -liveness-interval=30s
      vcap         275  0.0  0.0  70388  4016 pts/0    Ss   16:17   0:00 /bin/bash
      vcap         287  0.0  0.0  86284  3304 pts/0    R+   16:19   0:00 ps aux

      but I don't see my app there, although the app is available via URL, e.g.:

      %HOST%.launchpad.cfapps.eu10.hana.ondemand.com/UUID.app-name-0.0.10/index.html

      So, for which PID I have to execute kill -usr1 XXX?

      Author's profile photo Gregor Wolf
      Gregor Wolf

      Looks like you are connected to the approuter and not to your backend.

      Author's profile photo Mike B.
      Mike B.

      Gregor Wolf, I've followed the step #3 of this manual, I've got the name of the app via "cf apps" (it was the only option), then enabled the SSH via "cf enable-ssh %myapp%" and restarted my app with "cf restart %myapp%".

      So, the question how can I get connected to my app and not to the approuter?

      In start of the NPM-script inside of package.json, I run "node ./app.js", which creates an instance of approuter, configures the routing and starts the approuter. Should I revise the logic?

      Thanks.

      Author's profile photo Dhiraj More
      Dhiraj More

      Hi Arley Triana Morin Nice blog. Really looking for it for long time. few questions below.

      1. can we set the breakpoint for specific user, or it will only work for the user on which SSH is enabled by default.
      2. Do we have to restart the service everytime after SSH is enabled or it's one time activity.

      Thanks,

      Dhiraj M

      Author's profile photo Arley Triana Morin
      Arley Triana Morin
      Blog Post Author
      1. If you set an application breakpoint, the code will stop for all users unless you set a conditional breakpoint.
      2. A restart is usually required only after enabling SSH access. Once SSH is enabled, a restart isn't required.
      Author's profile photo Dhiraj More
      Dhiraj More

      Thanks Arley Triana Morin for response. However I have observed that although we have an active breakpoint but debugger is only stopping for first 1-2 times. Many times although i am running the process but debugger doesn't get executed.

      Is there any specific we have to do as I have observed this multiple times that after first 1-2 instances, control doesn't stop even breakpoint is in place and then again you have to kill session and follow the whole process again.

      Author's profile photo PRAVIN KUMAR
      PRAVIN KUMAR

      Dear Arley Triana Morin, Thanks for the blog, I've followed the same and have couple of questions

      1. After Step 4: Enable the Node.js Inspector for Remote Debugging on a Running Application Instance, There I couldn't find exact node /home/vcap/deps/0/bin/npx cds run rather

      user: remotetestapp $ cf ssh remotetestapp-srv
      vcap@36cc5bb8-1a96-413a-7756-a942:~$ ps aux
      USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
      root           1  0.0  0.0   1112     4 ?        Ss   05:24   0:00 /tmp/garden-init
      vcap           7  1.8  0.0 801996 73584 ?        Ssl  05:24   0:00 npm start
      vcap          13  0.0  0.0 724192  9860 ?        Ssl  05:24   0:00 /tmp/lifecycle/diego-sshd --allowedKeyExchanges= --address=0.0.0.0:
      root          21  0.0  0.0   4640   856 ?        Ss   05:24   0:00 sh -c trap 'kill -9 0' TERM; /etc/cf-assets/envoy/envoy -c /etc/cf-
      root          86  0.6  0.0 2759492 52416 ?       Sl   05:24   0:00 /etc/cf-assets/envoy/envoy -c /etc/cf-assets/envoy_config/envoy.yam
      vcap         186  0.0  0.0   4644   836 ?        S    05:24   0:00 sh /home/vcap/tmp/start-6e172f3b.sh
      vcap         187  2.7  0.0 11225584 94108 ?      Sl   05:24   0:00 node /home/vcap/app/node_modules/.bin/cds run
      root         198  0.0  0.0 714632  4216 ?        Ssl  05:24   0:00 /etc/cf-assets/healthcheck/healthcheck -port=8080 -timeout=1000ms -
      vcap         209  0.0  0.0  70392  3768 pts/0    Ss   05:24   0:00 /bin/bash
      vcap         220  0.0  0.0  86288  3348 pts/0    R+   05:25   0:00 ps aux

      Although I continue by killing PID 187, then followed port forwarding
      PFB attached Log

      Debugger listening on ws://127.0.0.1:9229/da338c78-3e2e-4c1f-8d04-63c3cf8be3ae

      2. After successful Port forwarding, I cant find the source code and  process.env.ADDR =undefined
      launch.json :

          {
            "name": "Attach to a Cloud Foundry Instance on Port 9229",
            "port": 9229,
            "request": "attach",
            "type": "node",
            "localRoot": "${workspaceFolder}",
            "remoteRoot": "/home/vcap/app"
          },

      Terminal :

      [cds] - using auth strategy: {kind: 'xsuaa'} 
      
      cds.version
      '6.3.2'
      process.ppid
      186
      process.env.ADDR
      undefined

      Same in case of Chrome Devtools, The Remote Target was Blank and can't interact with the REPL.

      Can you pls here, Is that something wrong I did?
      .

      Thanks,
      Pravin

       

      Author's profile photo Arley Triana Morin
      Arley Triana Morin
      Blog Post Author

      The same question has already been answered:

      https://answers.sap.com/questions/13768892/set-up-remote-debugging-to-diagnose-cap-applicatio.html?childToView=13780965

      Author's profile photo Christopher Thiele
      Christopher Thiele

      Hi Arley,

      do you know if there is a similar way how to do remote debugging of CAP applications on Kubernetes?

      Thanks,
      Christopher

      Author's profile photo Arley Triana Morin
      Arley Triana Morin
      Blog Post Author

      Yes, it is possible in a similar way to do remote debugging of CAP Applications (Node.js Stack) at Runtime on Kubernetes.

      Author's profile photo Pieter Janssens
      Pieter Janssens

      One liner, once ssh is enabled on the application, this needs to be repeated after each start/restart(/crash):

      cf ssh APP_NAME -c 'kill -usr1 $(pgrep node)' && cf ssh -N -T -L 9229:127.0.0.1:9229 APP_NAME