Max’s Adventure in SAP Cloud Platform: Debug your Java application in Cloud Foundry
Facing issues with your deployed Java application in Cloud Foundry (not particularly in SAP Cloud Platform, could be any Cloud Foundry environment) and you are not entirely sure what the root cause is? Most of the time debugging is an obvious solution approach. As long as the application is running on your own machine this might not be a challenge. But once your application is already deployed in Cloud Foundry..
There are numerous reasons for debugging an application. (not only those written Java) A few months ago I already wrote a blog post and philosophised a little about 😉 Have a read!
So, since this is a technical blog – I don’t want to drop more empty phrases.
What you need:
- A (free) Cloud Foundry space, e.g. in SAP Cloud Platform
- An installed Cloud Foundry CLI (Command Line Interface)->Tutorial to both of them can be found here: Get started with Cloud Foundry
- Some basic Java KnowHow: Building a Java app on your computer
- Some basic Cloud Foundry KnowHow: Pushing an application to a Cloud Foundry space
What you will do:
- Start your Java web server in DEBUG Mode
- Use Cloud Foundry SSH to forward traffic from remote ports to ports on your computer
- Configure Eclipse to debug remote applications
1) (optional) Set up your Java project:
If you don’t have a Java application yet and want to try debugging anyway, clone a random Java project (which is suited for Cloud Foundry). Either take one of the Cloud Foundry GitHub repositories, which are quite easy to clone and set up or even get started with tutorials for the S/4HANA Cloud SDK and also discover the capabilities of the recently released SDK.
2) Build your app
To produce a .war or .jar (i.e. spring boot) file, build your project by the following command in the folder where your pom.xml is located:
mvn clean package
3) Update your manifest.yml
You should usually have a manifest.yml to deploy your application to a Cloud Foundry Space. Mine, without any debug configuration, is:
--- applications: - name: myblogapp memory: 1024M instances: 1 path: target/HelloWorld-0.0.1-SNAPSHOT.war
To enable remote debugging, add an environment variable to configure the application server:
--- applications: - name: myblogapp memory: 1024M instances: 1 path: target/HelloWorld-0.0.1-SNAPSHOT.war env: JAVA_OPTS: "-agentlib:jdwp=transport=dt_socket,address=8686,server=y,suspend=n"
JAVA_OPTS is the standard environment variable that some servers and other java apps append to the call that executes the java command.
For example in tomcat if you define JAVA_OPTS=’-Xmx1024m’, the startup script will execute java org.apache.tomcat.Server -Xmx1024m.
What your additional line in the manifest.yml effectively does:
• transport=dt_socket : defines the transport mode used to connect to JVM (socket is a good choice, it can be used to debug a distant computer)
• address= 8686 : TCP/IP port exposed, to connect from the debugger,
• suspend=n : The suspend parameter of the -Xrunjdwp argument specifies whether you want to suspend the debugged JVM until the debugger attaches to it.
By default, the suspend parameter has the value “y“, which means that the virtual machine would be suspended before it had the opportunity to load the main class, and the attached debugger would resume the execution of the VM.
Since you usually need the web server to boot properly before you can debug your application, you should set the suspend parameter to “n“.
4) Push the application to Cloud Foundry
Before you can deploy your application to a Cloud Foundry space, you should be logged in to the according endpoint. If you are not yet familiar with the Cloud Foundry CLI make yourself familiar with it using this tutorial.
Deploy the application via:
5) Tunnel your configured port
As you set up your debugging port in step 3 to localhost:8686, this port is right now only available within your Cloud Foundry app instance, but not anywhere else. Thus you are going to use SSH to enable port forwarding.
SSH access can be enabled at different levels – either for an entire Cloud Foundry space or only for a certain app.
For the entire space:
cf allow-space-ssh [spacename] cf disallow-space-ssh [spacename]
In your specific case only for one app:
cf enable-ssh myblogapp cf disable-ssh myblogapp
Before you can go over to the actual port forwarding, the app must be restarted to take the enabled ssh statement into account.
cf restart myblogapp
Taken from the official Cloud Foundry documentation:
$ cf ssh MY-AWESOME-APP -L [LOCAL-NETWORK-INTERFACE:]LOCAL-PORT:REMOTE-HOST-NAME:REMOTE-HOST-PORT
For your specific case:
$ cf ssh myblogapp -L 8686:localhost:8686
This means that traffic going to port 8686 in your Cloud Foundry instance will be forwarded to the your computer on port 8686, to be more precise localhost:8686.
Too long; didn’t read? Or want to see it in action?
6) Get your Eclipse ready!
Two things are inevitable to debug remote applications in Eclipse: On the hand the source code of your application that you are able to set breakpoints. And also the debugger needs the source code to stop and visualize where the execution actually is. On the other hand, Eclipse needs to know the connection details of where it’s supposed to listen for traffic.
1. Import your project to Eclipse (if not already done)
2. Go to Run > Debug Configurations
3. Go to Run > Debug Configurations
4. Create a new Debug Configuration for a remote application. Enter the connection properties from your previous steps – localhost:8686 and chose the right Project.
7) Start the Debug Configuration
Attach your debugger to the according port on your localhost with the previously created Configuration. Also, set a breakpoint in your coding – otherwise the execution might not stop 😉
8) Gentleman, start your engine!
Hit the endpoint of your Cloud Foundry application or execute whatever logic in your application to stop at your breakpoint. Good luck fixing your bug 😉