Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support SentryCoroutineExceptionHandler #1524

Open
marandaneto opened this issue Jun 11, 2021 · 8 comments
Open

Support SentryCoroutineExceptionHandler #1524

marandaneto opened this issue Jun 11, 2021 · 8 comments

Comments

@marandaneto
Copy link
Contributor

marandaneto commented Jun 11, 2021

As we have a sentry-kotlin-extensions module right now and SentryContext for Coroutines, it'd be a nice addition offering a SentryCoroutineExceptionHandler, https://kotlinlang.org/docs/exception-handling.html#coroutineexceptionhandler
so people can use it and when it throws, it captures an event automatically, how does that sound?
Similar to our UncaughtExceptionHandlerIntegration

@marandaneto marandaneto added enhancement New feature or request kotlin-extensions labels Jun 11, 2021
@marandaneto
Copy link
Contributor Author

val handler = SentryCoroutineExceptionHandler { _, exception -> 
    // ideally we create an event with a mechanism
    Sentry.captureException(exception)
}
val job = GlobalScope.launch(handler) {
    throw AssertionError()
}

@marandaneto
Copy link
Contributor Author

examples can be found on https://github.com/Kotlin/kotlinx.coroutines/tree/master/kotlinx-coroutines-core/jvm/test/guide
example-exceptions-{number}-kt files

@marandaneto
Copy link
Contributor Author

works like a try/catch, if no CoroutineExceptionHandler is given, UncaughtExceptionHandlerIntegration gets called and crashes the App, but if a CoroutineExceptionHandler is given, it gets caught and swallowed, so its a bit less boilerplate than a try/catch but works the same way

@marandaneto
Copy link
Contributor Author

one thing to note is:

[CoroutineExceptionHandler] can be invoked from an arbitrary thread

so we cannot use the current thread when creating a ExceptionMechanismException

@marandaneto
Copy link
Contributor Author

marandaneto commented Jun 11, 2021

public object SentryCoroutineExceptionHandler : AbstractCoroutineContextElement(CoroutineExceptionHandler), CoroutineExceptionHandler {
    override fun handleException(context: CoroutineContext, exception: Throwable) {
        val mechanism = Mechanism().apply {
            // null and true is the same
            // isHandled = true
            type = "CoroutineExceptionHandler"
        }
        // cannot use the Thread.currentThread()
        // [CoroutineExceptionHandler] can be invoked from an arbitrary thread
        // ExceptionMechanismException should have an overload without a thread
        val error = ExceptionMechanismException(mechanism, exception, Thread.currentThread())
        val event = SentryEvent(error)
       // we probably need a hint here to not append anything from the `currentThread`
        Sentry.captureEvent(event)
    }
}
GlobalScope.launch(SentryCoroutineExceptionHandler) {
    throw AssertionError()
}

Screenshot 2021-06-11 at 10 31 16

@marandaneto
Copy link
Contributor Author

@marandaneto
Copy link
Contributor Author

Consider testing https://github.com/Anamorphosee/stacktrace-decoroutinator and adding to the docs if it gives better stack traces

@marandaneto
Copy link
Contributor Author

Relates to #2687 as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Backlog
Development

Successfully merging a pull request may close this issue.

4 participants