1**Table of contents** 2 3<!--- TOC --> 4 5* [Debugging coroutines](#debugging-coroutines) 6* [Debug mode](#debug-mode) 7* [Stacktrace recovery](#stacktrace-recovery) 8 * [Stacktrace recovery machinery](#stacktrace-recovery-machinery) 9* [Debug agent](#debug-agent) 10* [Android optimization](#android-optimization) 11 12<!--- END --> 13 14## Debugging coroutines 15 16Debugging asynchronous programs is challenging, because multiple concurrent coroutines are typically working at the same time. 17To help with that, `kotlinx.coroutines` comes with additional features for debugging: debug mode, stacktrace recovery 18and debug agent. 19 20## Debug mode 21 22The first debugging feature of `kotlinx.coroutines` is debug mode. 23It can be enabled either by setting system property [DEBUG_PROPERTY_NAME] or by running Java with enabled assertions (`-ea` flag). 24The latter is helpful to have debug mode enabled by default in unit tests. 25 26Debug mode attaches a unique [name][CoroutineName] to every launched coroutine. 27Coroutine name can be seen in a regular Java debugger, 28in a string representation of the coroutine or in the thread name executing named coroutine. 29Overhead of this feature is negligible and it can be safely turned on by default to simplify logging and diagnostic. 30 31## Stacktrace recovery 32 33Stacktrace recovery is another useful feature of debug mode. It is enabled by default in the debug mode, 34but can be separately disabled by setting `kotlinx.coroutines.stacktrace.recovery` system property to `false`. 35 36Stacktrace recovery tries to stitch asynchronous exception stacktrace with a stacktrace of the receiver by copying it, providing 37not only information where an exception was thrown, but also where it was asynchronously rethrown or caught. 38 39It is easy to demonstrate with actual stacktraces of the same program that awaits asynchronous operation in `main` function 40(runnable code is [here](../../kotlinx-coroutines-debug/test/RecoveryExample.kt)): 41 42| Without recovery | With recovery | 43| - | - | 44| ![before](../images/before.png "before") | ![after](../images/after.png "after") | 45 46The only downside of this approach is losing referential transparency of the exception. 47 48> Note that suppressed exceptions are not copied and are left intact in the cause 49> in order to prevent cycles in the exceptions chain, obscure`[CIRCULAR REFERENCE]` messages 50> and even [crashes](https://jira.qos.ch/browse/LOGBACK-1027) in some frameworks 51 52### Stacktrace recovery machinery 53 54This section explains the inner mechanism of stacktrace recovery and can be skipped. 55 56When an exception is rethrown between coroutines (e.g. through `withContext` or `Deferred.await` boundary), stacktrace recovery 57machinery tries to create a copy of the original exception (with the original exception as the cause), then rewrite stacktrace 58of the copy with coroutine-related stack frames (using [Throwable.setStackTrace](https://docs.oracle.com/javase/9/docs/api/java/lang/Throwable.html#setStackTrace-java.lang.StackTraceElement:A-)) 59and then throws the resulting exception instead of the original one. 60 61Exception copy logic is straightforward: 62 1) If the exception class implements [CopyableThrowable], [CopyableThrowable.createCopy] is used. 63 `null` can be returned from `createCopy` to opt-out specific exception from being recovered. 64 2) If the exception class has class-specific fields not inherited from Throwable, the exception is not copied. 65 3) Otherwise, one of the public exception's constructor is invoked reflectively with an optional `initCause` call. 66 4) If the reflective copy has a changed message (exception constructor passed a modified `message` parameter to the superclass), 67 the exception is not copied in order to preserve a human-readable message. [CopyableThrowable] does not have such a limitation 68 and allows the copy to have a `message` different from that of the original. 69 70## Debug agent 71 72[kotlinx-coroutines-debug](../../kotlinx-coroutines-debug) module provides one of the most powerful debug capabilities in `kotlinx.coroutines`. 73 74This is a separate module with a JVM agent that keeps track of all alive coroutines, introspects and dumps them similar to thread dump command, 75additionally enhancing stacktraces with information where coroutine was created. 76 77The full tutorial of how to use debug agent can be found in the corresponding [readme](../../kotlinx-coroutines-debug/README.md). 78 79<!--- 80Make an exception googlable 81java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/management/ManagementFactory; 82 at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent$ProcessProvider$ForCurrentVm$ForLegacyVm.resolve(ByteBuddyAgent.java:1055) 83 at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent$ProcessProvider$ForCurrentVm.resolve(ByteBuddyAgent.java:1038) 84 at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:374) 85 at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:342) 86 at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:328) 87 at kotlinx.coroutines.debug.internal.DebugProbesImpl.install(DebugProbesImpl.kt:39) 88 at kotlinx.coroutines.debug.DebugProbes.install(DebugProbes.kt:49) 89--> 90 91## Android optimization 92 93In optimized (release) builds with R8 version 1.6.0 or later both 94[Debugging mode](debugging.md#debug-mode) and 95[Stacktrace recovery](debugging.md#stacktrace-recovery) 96are permanently turned off. 97For more details see ["Optimization" section for Android](../../ui/kotlinx-coroutines-android/README.md#optimization). 98 99<!--- MODULE kotlinx-coroutines-core --> 100<!--- INDEX kotlinx.coroutines --> 101 102[DEBUG_PROPERTY_NAME]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-d-e-b-u-g_-p-r-o-p-e-r-t-y_-n-a-m-e.html 103[CoroutineName]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-name/index.html 104[CopyableThrowable]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-copyable-throwable/index.html 105[CopyableThrowable.createCopy]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-copyable-throwable/create-copy.html 106 107<!--- MODULE kotlinx-coroutines-debug --> 108<!--- END --> 109