Debug asynchronous code
Debugging asynchronous code is a challenge as the execution jumps between frames and makes it harder to follow the code. To help you look back from a specific point in the code, IntelliJ IDEA provides capture points.
A capture point is a place in your code where the debugger captures stack traces to be used later when you reach a specific point in the code (the insertion point) and want to see how you got there. A capture point is specified by the method name (and the containing class) and the key expression. When the debugger stops, it starts matching stack frames with the insertion point, which is another method and expression. If a match is found, the debugger evaluates the expression, and if the value has some related stack information, it replaces the rest of the call stack with the captured stack. This helps you see what was happening at the related capture point, and how you got to the present point.
Asynchronous stack traces are enabled by default (
). The most common capture points are built in, so no configuration is required.To try async stack traces, debug the following example:
Use async annotations
If you need capture points that are not included in the default configuration, you can use annotations that can be referenced in your code.
Add a dependency to the JetBrains Maven Java annotations repository for your artifacts and use the @Async.Schedule
and @Async.Execute
annotations in your code.
When a point annotated with @Async.Schedule
is reached, the current stack is saved in a storage map. When a point annotated with @Async.Execute
is reached, the debugger tries to find the related stack in the storage map.
You can annotate:
methods:
this
value is used as a keyparameters: the parameter value is used as a key
Define custom annotations
If for some reason you do not want to add the JetBrains Maven repository as a dependency for your project, you can define your own annotations and use them instead of the default ones.
Create your own annotations for the capture point and the insertion point (you can use Async.java for reference).
In the Settings/Preferences dialog (Ctrl+Alt+S), go to and click Configure annotations.
In the Async Annotations Configuration dialog, click to add your custom annotations to Async Schedule annotations and Async Execute annotations.
Configure capture points manually
If for some reason you cannot use annotations, or need to be able to capture local variables, you can configure capture points manually.
In the Settings/Preferences dialog (Ctrl+Alt+S) go to .
- Click to add a new capture point, and enter the information related to the capture point and the insertion point.
For example,
javax.swing.SwingUtilities.invokeLater
with thedoRun
key will capture all invocations of theinvokeLater
method and associate them with theRunnable
instance parameter.java.awt.event.InvocationEvent.dispatch
with therunnable
insert key will insert the information captured forinvokeLater
to the place whereRunnable
is executed. (Optional) If you also want to capture local variables (primitives and String values together with the call stack, select the Capture local variables option. Note that this may slow down the debugging process, and that this option is unavailable if the Instrumenting Agent is enabled.
You can download some additional capture settings from the following repository: IntelliJ IDEA debugger Capture Points
View Async Stack Traces in remote JVMs
If you are debugging a remote process, for example managed within a Docker container, you can still use the JVM Instrumenting Agent to display Async Stack Traces as if it were started from the IDE.
To use the agent remotely, do the following:
copy <IDEA installation folder>/lib/rt/debugger-agent.jar to any location on the remote machine
add
-javaagent:<path to debugger-agent.jar>
to the remote JVM options