debugging a Grails app from IntelliJ
Asked Answered
H

3

10

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

  1. functional tests can be debugged
  2. functional tests can be run
  3. the app can be debugged
  4. the app can be run

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

Debug run-app (3)

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.

Debug functional tests (1)

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.

Handknit answered 7/7, 2015 at 16:16 Comment(0)
A
6

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:

  • Add a new Run Configuration for your grails project. Use run-app --debug-fork as command line.
  • Add a new remote debug configuration. Just use the default settings.

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

Anse answered 8/7, 2015 at 15:48 Comment(0)
P
3

For debugging the app itself, starting from Grails 3 we can go to grails-app/init then right click on the Application.groovy class and click Debug 'Application'.

Plenipotentiary answered 5/6, 2021 at 17:21 Comment(0)
H
1

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.

Harrietteharrigan answered 23/1, 2016 at 16:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.