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 Running 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, following 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 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 pop 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

FIN

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

      15 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.