Remote debug or local debug with tomcat embedded in Spring boot - spring

I am working on a new project which embedded a tomcat with the dependency spring-boot-starter-tomcat:2.5.3 (into vaadin-spring-boot-starter).
I am building my project into a .jar, and launching it with "mvn spring-boot:run".
But because of the embedded tomcat, I am unable to use the debug mode with Eclipse.
I have already try to launch a remote debug session, with :
MAVEN_OPTS= -Xmx1024M -XX:MaxPermSize=256M -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000
Eclipse connects itself well, but breakpoints are not working and it shows me only one thread, without any more informations.
So, do you have any idea how can I make it works ?
Thanks you for your time !

When running application using mvn spring-boot:run you can attach debugger like this:
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=*:8000"
By providing spring-boot.run.jvmArguments system property.
Alternatively, you can build application first and then run it using the following command:
java -jar app.jar -Dagentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000
When you provide debugger configuration using MAVEN_OPTS, the debugger is attached to the Maven process, however, the application is running in a separate Java process without a debugger attached.

The easiest way to debug a Spring Boot application from an IDE is to not use Maven at all but instead directly launch the main method from the #SpringBootApplication class.

As a third solution, I have installed Spring Tools 4 on the Eclipse Marketplace.
It makes me able to launch a #SpringBootApplication in debug mode, like Leif Astrand said, but with an IHM (Boot Dashboard).

Another solution is described here:
https://vaadin.com/forum/thread/17519592/debug-with-intellij
This solution also helped me get around the problem of connecting the remote debugger, but breakpoints not being reached (see my comment above).
You can add a JVM arg to the config params of the plugin, like this:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!-- my edits start -->
<configuration>
<jvmArguments>
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000
</jvmArguments>
</configuration>
<!-- my edits end -->
</plugin>

Related

Running Spring Boot "context loads" test in maven causes OutOfMemoryError

I have a multi-module Maven project with two modules being Spring Boot applications. Each of them has a simple test that the Spring application context loads successfully (my tests are very similar to this one). I run this tests with the following command in project root:
mvn -P IntegrationTests clean test
During context initialization things go out of my control, the application "eats" memory (heap size grows quickly to 4 gigabytes) and then the context fails to start with java.lang.OutOfMemoryError: PermGen space error (yes, I run it in Java 7).
Monitoring task manager during testing I noticed that maven spawns two new processes that have something to do with surefire plugin. I have no idea where it comes from, because I don't add the surefire plugin in my pom.xml.
Previously when encountered the same error somewhere I specified VM options (-Xmx256m -Xms128m -XX:MaxPermSize=256m -XX:PermSize=128m for example) and the problem was solved.
This time I tried to
set MAVEN_OPTS environment variable
set VM options (when running mvn test in IntelliJ IDEA) - it affected main java process but not its children
add -Drun.jvmArguments="..." in command line
but the problem persists.
Please help me to fight the OutOfMemoryError in tests.
Add Surefire plugin explicitly to module-specific pom.xml and configure VM options there. I like this solution because this way VM options are
passed to the spawned surefire processes (which should solve your problem)
affect only test application builds
shared between developers in your team
configurable independently for every module
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Xmx256m -Xms128m -XX:MaxPermSize=256m -XX:PermSize=128m</argLine>
</configuration>
</plugin>
<!-- your other plugins go here -->
</plugins>
</build>

How to undeploy a .war with Jenkins?

we are working on our Selenium Grid Setup.
We did it like this:
We got 2x Jenkins Jobs and 2x Tomcats.
We are using Maven!
First Jenkins Job deploys the application (to test) on a tomcat. This job got a post action where the second job is triggered. (of course with ignored testing)
Second Jenkins Job tests the application deployed on the first tomcat and if its successful it will deploy the application on the second and final Tomcat.
Now we need to undeploy the application on the first Tomcat if its deployed on the second one.
Is there any option to integrate this in the second Jenkins Job?
It would be nice if you could give me some advice.
Thank you
-T
Typically, the way to deploy and undeploy on Tomcat in an automated fashion is to use the Maven Tomcat plugin. Disregard the fact that it seems to be only for Tomcat version 7 - it will work the same for 7+.
Behind the scenes, this plugin utilizes the Tomcat manager REST API.
Your Jenkins commands would probably go like:
mvn tomcat7:deploy on first server
If the deploy and startup is successful, you'll get a verifiable response that looks like: "OK - Deployed application at context path /foo" (and likely the relative error code)
You could also write a curl and parse command
for the manager command at http://localhost:8080/manager/text/list
to check if the application deployed as a sanity check
If it deployed
Do a mvn tomcat7:deploy on the second server and
Do a mvn tomcat7:undeploy on
the first server.
Just for all of the information to be here, the basic maven configuration for this plugin is:
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<url>http://localhost:8080/manager/text</url>
<server>TomcatServer</server>
<path>/myAppContextPath</path>
<username>admin</username>
<password>admin</password>
</configuration>
</plugin>

How can I configure the heap size when starting a Spring Boot application with embedded Tomcat?

I am trying to deploy a Spring Boot powered web app to production. The app is built with Spring Boot 1.0.1 and has the default Tomcat 7 embedded as application server. I want to allocate larger memory to the app when start the app with java -jar myapp.jar command line.
Should I use JVM parameter such as -Xms -Xmx or use environment variable such as JAVA_OPTS? I have tried to look for the answer in documentation or google it, but I did not get an answer. Can anyone give some hints?
If starting the application with the spring-boot plugin:
mvn spring-boot:run -Drun.jvmArguments="-Xmx512m" -Drun.profiles=dev
Otherwise if running java -jar:
java -Xmx512m -Dspring.profiles.active=dev -jar app.jar
Since this is specifically a Spring Boot question, I'd argue that a more useful answer than #DaveSyer's is this:
You can drop a .conf file in the same directory as your WAR file that is effectively a shell script.
For example,
$ ls
myapp.conf
myapp.war
$ cat myapp.conf
export JAVA_OPTS="-Xmx1024m -Xms256m"
Any configuration you do there will be run before the Spring Boot embedded Tomcat starts up. Personally, I version control a .conf.example file in my application itself and then drop a copy of it on each server I deploy to.
Of course, anything you set in that .conf file is overridable with command-line operations.
Just use whatever normal mechanism you would to set up the JVM. Documentation is available on the command line:
$ java -X
...
-Xms<size> Set initial Java heap size
-Xmx<size> Set maximum Java heap size
...
For Spring Boot 2, you have to specify the heap size in the pom.xml file as below:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<jvmArguments>-Xmx64m</jvmArguments>
</configuration>
</plugin>
For Spring Boot 1, the Maven argument to specify in the plugin configuration is jvmArguments, and the user property is run.jvmArguments:
mvn spring-boot:run -Drun.jvmArguments="-Xms2048m -Xmx4096m"
For Spring Boot 2, the Maven argument to specify in the plugin configuration is also jvmArguments, but the user property is now spring-boot.run.jvmArguments:
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-Xms2048m -Xmx4096m"
So if you use the plugin configuration way, both for Spring Boot 1 and 2 you can do that:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<jvmArguments>
-Xms4048m
-Xmx8096m
</jvmArguments>
</configuration>
</plugin>

Intellij-idea Debugger disconnected when debugging maven test

I have followed this link to debug maven test via Intellij Idea : http://www.grygoriy.com/2012/01/how-to-debug-tests-maven-test-via.html
When reaching the third step and starting debugging, It's connected but quickly disconnected and isn't stopped in breakpoints. I had in Intellij :
Connected to the target VM, address: 'localhost:5005', transport: 'socket'
Disconnected from the target VM, address: 'localhost:5005', transport: 'socket'
Any idea ?
The only thing that prevents Idea from debugging Maven's goals is forking.
Plugins such surefire and spring-boot are using forking by default.
So, when you start debuging maven goal from IDEA it connects to maven, but process that you are really want to debug distincts from maven process, so it doesn't connected.
To prevent such behavior in surefire plugin you should read this article: http://maven.apache.org/surefire/maven-surefire-plugin/examples/fork-options-and-parallel-execution.html
In short:
If you use old surefire:
<configuration>
<forkMode>never</forkMode>
</configuration>
In new surefire:
<configuration>
<forkCount>0</forkCount>
</configuration>
But it's not much clear:
in case of CI (i wish you are using CI tools) you are not have prevent forking while it's much slow
if you ship your project to others - they will not be happy if some of modules behave in not default way
So if you want to please CI, IDEA, co-developers and yourself you should provide more smart way to allow debugging you build.
My suggestion:
default behavior is forked because build process is very often thing, while debugging it - is exception
debugger behavior is isolated with simple to use "switch on"
My variant:
<properties>
<test.forkCount>1</test.forkCount>
</properties>
<profiles>
<profile>
<id>debug</id>
<properties>
<test.forkCount>0</test.forkCount>
</properties>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<!-- surefire -->
<configuration>
<forkCount>${test.forkCount}</forkCount>
</configuration>
</plugin>
</plugins>
</build>
So, in IDEA you just require to create named Run configuration with goal test and include debug to profile list.
But in other contexts - maven behaves still by default.
Where is addition profit - you can incapsulate whole debug behavior in single profile.
For example in my real project debug profile:
swith off forking on spring-boot:run
switch off JaCoCo coverage (it requires forking on surefire)
keep building Docker images locally but prevents pushing to registry
keep full packaging process but prevents publication to nexus
redirects SOAP UI functional tests to specital URL for local debugging
redirects DBCONFIG to docker-based Postgres that is "always empty"
downgrades loglevel for log4j to DEBUG
So if I use mvn <any> -P debug i'm sure that my environment and process is really debug
But if i ran mvn deploy on CI - i will get full stack of my building process.
This can also happen if e.g. the annotation BeforeAll is incorrectly used. IntelliJ swallows problem during the test initialization.
In my case the BeforeAll method was not static:
Incorrect:
#BeforeAll
private void beforeAll() {
}
It can also happen if the BeforeAll method is failing and the test is not started. Using mvn verify should print the error message in these cases.

Debug web app in IntelliJ, webapp built by maven, run by jetty

I'm using s/o code, it's a java webapp built by maven. The webapp is run by maven script, like below, and the app is run on localhost:8080, :
<build>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.8.v20121106</version>
<configuration>
<contextPath>/</contextPath>
<connectors>
<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
<!--<port>8085</port>-->
<port>8080</port>
<maxIdleTime>60000</maxIdleTime>
</connector>
</connectors>
<stopKey>stop</stopKey>
<stopPort>8089</stopPort>
</configuration>
</plugin>
</plugins>
</build>
I want to attach the debugger of IntelliJ so that I can step through the code. I tried to set up a debugger configuration like: Jetty Server, then 'Remote' but it said Application Server not specified. I also tried with 'Local', it said 'main config file not included'.
So what must I do to attach the debugger?
Thanks in advance.
The easiest way is to:
Expand your project in the Maven Projects tab.
Expand Plugins > jetty items.
Right-click jetty:run.
Choose Debug from the context menu.
I know it's too late to reply this question, but It's worth sharing the latest update on this issue as a modern solution: You can also run jetty using “mvnDebug jetty:run” which has the same effect. Which display the following logs in the terminal
Preparing to Execute Maven in Debug Mode
Listening for transport dt_socket at address: 8000
[INFO] Scanning for projects...
Just remember to choose the correct socket address(e.g. 8000), then:
Open Intellij
Run -> Edit Configuration
In Run/Debug Configuration window, you need to click on (+) button to add a new configuration
Select Remote
Keep the default configuration as is, just change the listening port to corresponding one (8000).
Enjoy.
When I was getting "main config file not included" it was because the path to Jetty in my Application Server configuration (on Run/Debug Configurations dialog) was deleted during my OS X upgrade (I had put it in /usr/share/java).
I reinstalled jetty-hightide-8.1.5.v20120716 under /usr/local, updated the configuration and all is well.

Resources