blob: f9260d825c17aec70f0bed120a6dca70fe01ba26 [file] [log] [blame] [view]
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +03001**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)
Vsevolod Tolstopyatov4764e982019-02-04 12:39:34 +030010 * [Debug agent and Android](#debug-agent-and-android)
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030011
12<!--- END_TOC -->
13
14
15## Debugging coroutines
16Asynchronous programming is hard and debugging asynchronous programs is even harder.
17To improve user experience, `kotlinx.coroutines` comes with additional features for debugging: debug mode, stacktrace recovery
18and debug agent.
19
20## Debug mode
Vsevolod Tolstopyatova68376c2019-02-01 18:13:39 +030021
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030022The 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, which then can be seen in a regular Java debugger,
27a string representation of coroutine and thread name executing named coroutine.
28Overhead of this feature is negligible and it can be safely turned on by default to simplify logging and diagnostic.
29
30## Stacktrace recovery
Vsevolod Tolstopyatova68376c2019-02-01 18:13:39 +030031
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030032Stacktrace recovery is another useful feature of debug mode. It is enabled by default in the debug mode,
33but can be separately disabled by setting `kotlinx.coroutines.stacktrace.recovery` system property to `false`.
34
35Stacktrace recovery tries to knit asynchronous exception stacktrace with a stacktrace of the receiver by copying it, providing
Vsevolod Tolstopyatov4764e982019-02-04 12:39:34 +030036not only information where an exception was thrown, but also where it was asynchronously rethrown or caught.
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030037
38It is easy to demonstrate with actual stacktraces of the same program that awaits asynchronous operation in `main` function:
39
40| Without recovery | With recovery |
41| - | - |
42| ![before](images/before.png "before") | ![after](images/after.png "after") |
43
44The only downside of this approach is losing referential transparency of the exception.
45
46### Stacktrace recovery machinery
Vsevolod Tolstopyatova68376c2019-02-01 18:13:39 +030047
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030048This section explains the inner mechanism of stacktrace recovery and can be skipped.
49
50When an exception is rethrown between coroutines (e.g. through `withContext` or `Deferred.await` boundary), stacktrace recovery
51machinery tries to create a copy of the original exception (with the original exception as the cause), then rewrite stacktrace
52of 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-))
53and then throws resulting exception instead of the original one.
54
55Exception copy logic is straightforward:
56 1) If exception class implements [CopyableThrowable], [CopyableThrowable.createCopy] is used.
57 2) If exception class has class-specific fields not inherited from Throwable, the exception is not copied.
58 3) Otherwise, one of the public exception's constructor is invoked reflectively with optional an `initCause` call.
59
60## Debug agent
Vsevolod Tolstopyatova68376c2019-02-01 18:13:39 +030061
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030062[kotlinx-coroutines-debug](../kotlinx-coroutines-debug) module provides one of the most powerful debug capabilities in `kotlinx.coroutines`.
63
64This is a separate module with a JVM agent that keeps track of all alive coroutines, introspect and dump them similar to thread dump command,
65additionally enhancing stacktraces with information where coroutine was created.
66
67The full tutorial of how to use debug agent can be found in a corresponding [readme](../kotlinx-coroutines-debug/README.md).
68
Vsevolod Tolstopyatova68376c2019-02-01 18:13:39 +030069### Debug agent and Android
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030070
Vsevolod Tolstopyatova68376c2019-02-01 18:13:39 +030071Unfortunately, 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;`.
72
73Nevertheless, it will be possible to support debug agent on Android as soon as [GradleAspectJ-Android](https://github.com/Archinamon/android-gradle-aspectj) will support androin-gradle 3.3
74
75<!---
76Make an exception googlable
77java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/management/ManagementFactory;
78 at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent$ProcessProvider$ForCurrentVm$ForLegacyVm.resolve(ByteBuddyAgent.java:1055)
79 at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent$ProcessProvider$ForCurrentVm.resolve(ByteBuddyAgent.java:1038)
80 at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:374)
81 at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:342)
82 at kotlinx.coroutines.repackaged.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:328)
83 at kotlinx.coroutines.debug.internal.DebugProbesImpl.install(DebugProbesImpl.kt:39)
84 at kotlinx.coroutines.debug.DebugProbes.install(DebugProbes.kt:49)
85-->
Vsevolod Tolstopyatov418ba802019-02-01 14:54:06 +030086
87<!--- MODULE kotlinx-coroutines-core -->
88<!--- INDEX kotlinx.coroutines -->
89[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
90[CoroutineName]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-name/index.html
91[CopyableThrowable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-copyable-throwable/index.html
92[CopyableThrowable.createCopy]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-copyable-throwable/create-copy.html
93<!--- MODULE kotlinx-coroutines-debug -->
94<!--- END -->