How to: Debug webb app started with gradle/gretty

Answered

Unfortunately it is a little complicated to debug your web app when using gradle. What I found, describes how you can configure options/run configurations manually to get remote debugging to work, for example: https://github.com/akhikhl/gretty/issues/36
Unfortunately that always requires you to start both appStartDebug run configuration and a separate "remote debug" run configuration.

Here is a simple way, that allows you to just click "debug" in the "appStart" run configuration:

You need to make a small change to your build.gradle, to set JVM args in case of debugging:


// Enable debugging of gretty started webapp in IDEA
// For debuging a gradle task, IDEA creates a gradle init script (in /tmp/ijinit#.gradle), that sets JVM arguments
// to enable remote debugging.
// Unfortunately by default that only works for gradle tasks that implement JavaForkOptions - which gretty doesn't do.
// So parse the JVM args that IDEA uses from that init script and set them as JVM args to be used by gretty:
def debugArgs = []
if (gradle.startParameter.initScripts) {
def line = file(gradle.startParameter.initScripts[0]).readLines().findAll({x -> x ==~ /.*-agentlib:jdwp=.*/ })[0]
if (line) {
debugArgs = ((line =~ /.*'(.*)'.*/)[0][1] as String).split(' ')
}
}

gretty {
jvmArgs = [*debugArgs]
...
}

 

 

5 comments
Comment actions Permalink

It works thank you ! But it sucks to have to do this kind of thing when using the best IDE and the (supposedly) best build system...

0
Comment actions Permalink

There is a ticket to address gradle related problems:

https://youtrack.jetbrains.com/issue/IDEA-119494

0
Comment actions Permalink

I've been using this workaround for some time now, but IntelliJ has changed the way the initScripts are built. Now they follow this structure:

 

//-- Generated by org.jetbrains.plugins.gradle.service.project.BaseGradleProjectResolverExtension
initscript {
  dependencies {
    classpath files("/home/guillermo/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-0/182.4129.33/lib/external-system-rt.jar")
  }
}
gradle.taskGraph.beforeTask { Task task ->
  if (task instanceof org.gradle.api.tasks.testing.Test) {
    task.maxParallelForks = 1
    task.forkEvery = 0
  }
  if (task instanceof JavaForkOptions) {
    def jvmArgs = task.jvmArgs.findAll{!it?.startsWith('-agentlib:jdwp') && !it?.startsWith('-Xrunjdwp')}
    jvmArgs << com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper.setupDebugger(task.path, 44701)
    task.jvmArgs = jvmArgs
  }
}
gradle.taskGraph.afterTask { Task task ->
  if (task instanceof JavaForkOptions) {
    com.intellij.openapi.externalSystem.rt.execution.ForkedDebuggerHelper.processFinished(task.path, 44701)
  }
}

 

 

I've checked the Gretty project and they haven't updated it yet. Is there any modern alternative that uses JavaForkOptions?

0
Comment actions Permalink

Hi Guille,

This is a terribly hacky workaround which no one should ever use, but it works fine for me.

As with regular gretty, to terminate instances of gretty run this way, don't terminate using the IDEA debugger, but instead run 'gradle jettyStop' in another terminal window. Otherwise you will get hanging gretty processes.

Copy paste into your build.gradle:

def debugArgs = []
if (gradle.startParameter.initScripts) {

def all_lines = file(gradle.startParameter.initScripts[0]).text

def firstPattern = "setupDebugger(task.path, "
def firstIndex = all_lines.indexOf(firstPattern)
def debugPort = ""
if (firstIndex > 0) {
def secondIndex = all_lines.indexOf(")", firstIndex)
if (secondIndex > 0) {
debugPort = all_lines.substring(firstIndex + firstPattern.length(), secondIndex)
}
}

if (!debugPort.empty) {

def socket = null
def stream = null
try {
socket = new Socket("127.0.0.1", Integer.parseInt(debugPort))
stream = new DataOutputStream(socket.getOutputStream())
stream.writeInt(10700)
stream.writeUTF(":jettyStart")
socket.getInputStream().read();
}
catch(Exception e) {}
finally {
if (socket != null) socket.close()
if (stream != null) stream.close()
}

debugArgs = ["-agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=10700"]
}
}

gretty {
jvmArgs = [*debugArgs]
...
}



Use at your own risk!!!
1
Comment actions Permalink

Thanks for the hack! I'll give it a try. I'm aware of the requirement of stopping Jetty instances manually, so I think that your script would let me continue as always. I've also created an issue on Gretty's GitHub page requesting to make Gretty tasks implement JavaForkOptions, which would solve this issue once and for all. It would be great to have some +1 there from ppl affected by this ;) 

https://github.com/akhikhl/gretty/issues/435

0

Please sign in to leave a comment.