Using CoroutineExceptionHandler
val handler = CoroutineExceptionHandler { _, exception -> Timber.e(exception, "handler")}GlobalScope.launch(Dispatchers.Main + handler) { throw Exception("Test")}
NOTE: Using Timber for Android Logging.
handler
will only capture uncaught/unhandled exception. If you surround try/catch
as per the example below, handler
shall not be called.
GlobalScope.launch(Dispatchers.Main + handler) { try { throw Exception("Caught") } catch (e: Exception) { Timber.e(e, "catch") } throw Exception("for handler")}
Coroutines Stack Trace Caveats
Beaware that coroutines exception handling might not be able to property recover stack trace.
- https://github.com/Kotlin/kotlinx.coroutines/issues/74
- https://github.com/Kotlin/kotlinx.coroutines/issues/493
- https://github.com/Kotlin/kotlinx.coroutines/pull/502
- https://github.com/Kotlin/kotlinx.coroutines/pull/792
val deferred = GlobalScope.async { throw RuntimeException("Test Stacktrace")}GlobalScope.launch(Dispatchers.Main + handler) { deferred.await()}
Log
05-13 00:04:36.183 20975-20975/* E/TestFragment$initUi$3$$: handler
java.lang.RuntimeException: Test Stacktrace
at *.TestFragment$initUi$3$deferred$1.invokeSuspend(TestFragment.kt:107)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:238)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742)
- the main clue is
TestFragment.kt:107
, which point tothrow RuntimeException("Test Stacktrace")
- no indication that
throw RuntimeException("Test Stacktrace")
is called bydeferred.await()
- another clue is
TestFragment$initUi$3$$: handler
, indicate the exception happens ininitUi
function with the messagehandler
.