I've been struggling to debug a Grails 2.5.0 app from inside IntelliJ. Specifically, I'm finding it difficult to configure the app such that
when (1) and (2) are launched from inside IntelliJ (version 14.1.4).
Here's a toy Grails app I'm using to investigate this issue, which has a single functional test. The key to getting debugging working seems to be these JVM forking settings BuildConfig.groovy.
grails.project.fork = [
// configure settings for compilation JVM, note that if you alter the Groovy version forked compilation is required
// compile: [maxMemory: 256, minMemory: 64, debug: false, maxPerm: 256, daemon:true],
// configure settings for the test-app JVM, uses the daemon by default
test : [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, daemon: true, jvmArgs: jvmArgs],
// configure settings for the run-app JVM
run : [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve: false, jvmArgs: jvmArgs],
// configure settings for the run-war JVM
war : [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve: false],
// configure settings for the Console UI JVM
console: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256]
]
// Include the line below to debug functional tests from IntelliJ. The tests should be launched in Debug mode from IntelliJ
//grails.project.fork = null
With forking enabled, the app can be debugged by running it from inside IntelliJ, then launching a remote debugger from the IDE to connect to the app on port 5005. The JVM forking settings ensures that the app always runs with remote debugging enabled, so be sure to launch the app by running it, rather than debugging it.
To debug functional tests, you need to include this line
grails.project.fork = null
such that forking (and remote debugging is disabled. Then you can debug the functional tests by launching the test via an IntelliJ debug configuration.
It's fairly tedious to have to include/comment out this line depending on whether it's the app or a functional test that's being debugged, so I'm looking for a simpler solution.
One might think this could be avoided with
if (Environment.current == Environment.TEST) {
grails.project.fork = null
}
But for some unknown reason, this does not work.
Support for the Grails framework is not bundled with IntelliJ IDEA. You can install the Grails plugin from the JetBrains repository as described in Install plugins. The latest compatible version of IntelliJ IDEA is 2021.3. You can find the documentation for Grails support in earlier versions of IntelliJ IDEA Help.
Run the program in debug modeClick the Run icon in the gutter, then select Modify Run Configuration. Enter arguments in the Program arguments field. Click the Run button near the main method. From the menu, select Debug.
If you do have a lot of scriptlet code in your GSPs (which you shouldn't), and you want to debug into it, you can't do much more than println . One other possibility is to view the source of the Groovy code generated for your GSP. This can be done by appending a showSource parameter to the URL, as described here.
I have the following settings in BuildConfig.groovy
:
grails.project.fork = [
// configure settings for the test-app JVM, uses the daemon by default
test: false, // see http://youtrack.jetbrains.com/issue/IDEA-115097
// configure settings for the run-app JVM
run: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve:false],
// configure settings for the run-war JVM
war: false,
// configure settings for the Console UI JVM
console: false
]
You will need to add 2 run configurations in intellij:
run-app --debug-fork
as command line.To debug you app, run the first configuration. The grails app will start and should print Listening for transport dt_socket at address: 5005
. Once you see this message, run the debug configuration...
Let me know if you need screenshots
There is good hack for starting remote debug without wating for "Listening for transport dt_socket at address: 5005" line. Just run remote debug and run-app
In few words:
BuildConfig.groovy
// jvmArgs make it so that we can run in forked mode without having to use the `--debug-fork` flag
// and also has suspend=n so that it will start up without forcing you to connect a remote debugger first
def jvmArgs = ['-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005']
grails.project.fork = [
test: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, daemon:true, jvmArgs: jvmArgs],
run: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve:false, jvmArgs: jvmArgs],
war: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve:false, jvmArgs: jvmArgs],
console: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, jvmArgs: jvmArgs]
]
Monitor the port before starting the remote debugger
If you create a new remote debug target in intellij and run it at the same time as you run your app or tests, it’ll fail because the debug port isn’t open yet. If you do it manually, you need to wait for the log message saying that the debug port is open. That’s more babysitting that we can avoid through a little shell script trickery.
Here is a shell script that uses the nc (netcat) command to monitor a localhost port, and will only continue once the port is available. Save it as wait_for_port.sh somewhere in your path:
#!/usr/bin/env bash
PORT_NUMBER="$1"
function usage {
echo "usage: ${0##*/} "
echo "ex: ${0##*/} 5005"
}
if [ -z $PORT_NUMBER ]; then
usage
exit 1
fi
echo "waiting for port $PORT_NUMBER to open up"
while ! nc -z localhost $PORT_NUMBER; do sleep 0.1; done;
have it use this script as an “external tool” to monitor port 5005 before it tries to connect.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With