• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * [Debug agent and Android](#debug-agent-and-android)
11* [Android optimization](#android-optimization)
12
13<!--- END -->
14
15## Debugging coroutines
16
17Debugging asynchronous programs is challenging, because multiple concurrent coroutines are typically working at the same time.
18To help with that, `kotlinx.coroutines` comes with additional features for debugging: debug mode, stacktrace recovery
19and debug agent.
20
21## Debug mode
22
23The first debugging feature of `kotlinx.coroutines` is debug mode.
24It can be enabled either by setting system property [DEBUG_PROPERTY_NAME] or by running Java with enabled assertions (`-ea` flag).
25The latter is helpful to have debug mode enabled by default in unit tests.
26
27Debug mode attaches a unique [name][CoroutineName] to every launched coroutine.
28Coroutine name can be seen in a regular Java debugger,
29in a string representation of the coroutine or in the thread name executing named coroutine.
30Overhead of this feature is negligible and it can be safely turned on by default to simplify logging and diagnostic.
31
32## Stacktrace recovery
33
34Stacktrace recovery is another useful feature of debug mode. It is enabled by default in the debug mode,
35but can be separately disabled by setting `kotlinx.coroutines.stacktrace.recovery` system property to `false`.
36
37Stacktrace recovery tries to stitch asynchronous exception stacktrace with a stacktrace of the receiver by copying it, providing
38not only information where an exception was thrown, but also where it was asynchronously rethrown or caught.
39
40It is easy to demonstrate with actual stacktraces of the same program that awaits asynchronous operation in `main` function
41(runnable code is [here](../kotlinx-coroutines-debug/test/RecoveryExample.kt)):
42
43| Without recovery | With recovery |
44| - | - |
45| ![before](images/before.png "before") | ![after](images/after.png "after") |
46
47The only downside of this approach is losing referential transparency of the exception.
48
49### Stacktrace recovery machinery
50
51This section explains the inner mechanism of stacktrace recovery and can be skipped.
52
53When an exception is rethrown between coroutines (e.g. through `withContext` or `Deferred.await` boundary), stacktrace recovery
54machinery tries to create a copy of the original exception (with the original exception as the cause), then rewrite stacktrace
55of 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-))
56and then throws the resulting exception instead of the original one.
57
58Exception copy logic is straightforward:
59  1) If the exception class implements [CopyableThrowable], [CopyableThrowable.createCopy] is used.
60     `null` can be returned from `createCopy` to opt-out specific exception from being recovered.
61  2) If the exception class has class-specific fields not inherited from Throwable, the exception is not copied.
62  3) Otherwise, one of the public exception's constructor is invoked reflectively with an optional `initCause` call.
63
64## Debug agent
65
66[kotlinx-coroutines-debug](../kotlinx-coroutines-debug) module provides one of the most powerful debug capabilities in `kotlinx.coroutines`.
67
68This is a separate module with a JVM agent that keeps track of all alive coroutines, introspects and dumps them similar to thread dump command,
69additionally enhancing stacktraces with information where coroutine was created.
70
71The full tutorial of how to use debug agent can be found in the corresponding [readme](../kotlinx-coroutines-debug/README.md).
72
73### Debug agent and Android
74
75Unfortunately, Android runtime does not support Instrument API necessary for `kotlinx-coroutines-debug` to function, triggering `java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/management/ManagementFactory;`.
76
77Nevertheless, it will be possible to support debug agent on Android as soon as [GradleAspectJ-Android](https://github.com/Archinamon/android-gradle-aspectj)  will support android-gradle 3.3
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](../../docs/debugging.md#debug-mode) and
95[Stacktrace recovery](../../docs/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[DEBUG_PROPERTY_NAME]: https://kotlin.github.io/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
102[CoroutineName]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-name/index.html
103[CopyableThrowable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-copyable-throwable/index.html
104[CopyableThrowable.createCopy]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-copyable-throwable/create-copy.html
105<!--- MODULE kotlinx-coroutines-debug -->
106<!--- END -->
107