Skip to content

Commit 418ba80

Browse files
committed
Additional documentation section about debug mode and stacktrace recovery.
Not included in a guide intentionally
1 parent 4ba30cd commit 418ba80

File tree

4 files changed

+74
-0
lines changed

4 files changed

+74
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ GlobalScope.launch {
5757
* [Guide to kotlinx.coroutines by example](docs/coroutines-guide.md) (**read it first**)
5858
* [Guide to UI programming with coroutines](ui/coroutines-guide-ui.md)
5959
* [Guide to reactive streams with coroutines](reactive/coroutines-guide-reactive.md)
60+
* [Debugging capabilities in kotlinx.coroutines](docs/debugging.md)
6061
* [Change log for kotlinx.coroutines](CHANGES.md)
6162
* [Coroutines design document (KEEP)](https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md)
6263
* [Full kotlinx.coroutines API reference](http://kotlin.github.io/kotlinx.coroutines)

docs/debugging.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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+
11+
<!--- END_TOC -->
12+
13+
14+
## Debugging coroutines
15+
Asynchronous programming is hard and debugging asynchronous programs is even harder.
16+
To improve user experience, `kotlinx.coroutines` comes with additional features for debugging: debug mode, stacktrace recovery
17+
and debug agent.
18+
19+
## Debug mode
20+
The first debugging feature of `kotlinx.coroutines` is debug mode.
21+
It can be enabled either by setting system property [DEBUG_PROPERTY_NAME] or by running Java with enabled assertions (`-ea` flag).
22+
The latter is helpful to have debug mode enabled by default in unit tests.
23+
24+
Debug mode attaches a unique [name][CoroutineName] to every launched coroutine, which then can be seen in a regular Java debugger,
25+
a string representation of coroutine and thread name executing named coroutine.
26+
Overhead of this feature is negligible and it can be safely turned on by default to simplify logging and diagnostic.
27+
28+
## Stacktrace recovery
29+
Stacktrace recovery is another useful feature of debug mode. It is enabled by default in the debug mode,
30+
but can be separately disabled by setting `kotlinx.coroutines.stacktrace.recovery` system property to `false`.
31+
32+
Stacktrace recovery tries to knit asynchronous exception stacktrace with a stacktrace of the receiver by copying it, providing
33+
not only information where an exception was thrown, but also where it was asynchronously rethrown or caught .
34+
35+
It is easy to demonstrate with actual stacktraces of the same program that awaits asynchronous operation in `main` function:
36+
37+
| Without recovery | With recovery |
38+
| - | - |
39+
| ![before](images/before.png "before") | ![after](images/after.png "after") |
40+
41+
The only downside of this approach is losing referential transparency of the exception.
42+
43+
### Stacktrace recovery machinery
44+
This section explains the inner mechanism of stacktrace recovery and can be skipped.
45+
46+
When an exception is rethrown between coroutines (e.g. through `withContext` or `Deferred.await` boundary), stacktrace recovery
47+
machinery tries to create a copy of the original exception (with the original exception as the cause), then rewrite stacktrace
48+
of 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-))
49+
and then throws resulting exception instead of the original one.
50+
51+
Exception copy logic is straightforward:
52+
1) If exception class implements [CopyableThrowable], [CopyableThrowable.createCopy] is used.
53+
2) If exception class has class-specific fields not inherited from Throwable, the exception is not copied.
54+
3) Otherwise, one of the public exception's constructor is invoked reflectively with optional an `initCause` call.
55+
56+
## Debug agent
57+
[kotlinx-coroutines-debug](../kotlinx-coroutines-debug) module provides one of the most powerful debug capabilities in `kotlinx.coroutines`.
58+
59+
This is a separate module with a JVM agent that keeps track of all alive coroutines, introspect and dump them similar to thread dump command,
60+
additionally enhancing stacktraces with information where coroutine was created.
61+
62+
The full tutorial of how to use debug agent can be found in a corresponding [readme](../kotlinx-coroutines-debug/README.md).
63+
64+
65+
66+
<!--- MODULE kotlinx-coroutines-core -->
67+
<!--- INDEX kotlinx.coroutines -->
68+
[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
69+
[CoroutineName]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-name/index.html
70+
[CopyableThrowable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-copyable-throwable/index.html
71+
[CopyableThrowable.createCopy]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-copyable-throwable/create-copy.html
72+
<!--- MODULE kotlinx-coroutines-debug -->
73+
<!--- END -->

docs/images/after.png

290 KB
Loading

docs/images/before.png

158 KB
Loading

0 commit comments

Comments
 (0)