Ktor で例外発生時に Sentry にクラッシュレポートを送る
最近、個人で web アプリケーションを書くのに Ktor (Kotlin の web アプリケーションフレームワーク) を使っています。
Ktor では、1 つ以上の 「インターセプタ (interceptor)」 から成る 「パイプライン (pipeline)」 にリクエストを通すことで、HTTP リクエストに対する処理が実行されます。 各インターセプタがリクエストに対して処理を行う、という形です。 パイプラインについての詳細なドキュメントはまだ未整備な状態 *1 ですが、Application
の説明の方にパイプラインについても簡単に書かれています。
Sentry にクラッシュレポートを送る
今回は、後段のインターセプタで例外が発生した際に Sentry にクラッシュレポートを送るためのインターセプタを書いてみました。
Application
クラスの intercept
メソッド *2 を呼び、インターセプタを追加します。
fun Application.main() { // ... (略) ... Sentry.init(sentryDsn) // Application#intercept メソッドでインターセプタを追加する。 intercept(ApplicationCallPipeline.Call) { try { proceed() } catch (e: Exception) { // 追加情報としてリクエストのエンドポイントの情報を与える。 Sentry.getContext().addExtra( "Request endpoint", "${call.request.httpMethod.value} ${call.request.uri}") Sentry.capture(e) throw e } finally { Sentry.clearContext() } } // ... (略) ...
Sentry
クラスなどは Sentry 公式の sentry ライブラリのものです。
悩み事
Ktor ではコルーチンが使われているため、各リクエストに対して 1 スレッドが割り当てられる、というわけではありません。 一方で、sentry ライブラリのコンテキストマネージャはデフォルトだとスレッドローカル変数を使用してコンテキストが分かれるような作りになっていて、Ktor の処理の中の様々な場所で Sentry のコンテキストを触ろうとするとスレッド違いなどを意識しないといけなくて難しそう、だと思ってます。
上の例では同じスレッド上でコンテキストを触っているので問題ないのですが、もうちょっと込み入ったことをしたくなると不便そうです。 コンテキスト管理をスレッドローカル変数でやるのは悪い文化。
Ktor でクラッシュレポートを Sentry に送るライブラリ
ライブラリもあります。 が、まだスナップショットでしかリリースしてなさそう? なので私は避けました。
本記事でのバージョン
- Kotlin 1.2.10
- Ktor 0.9.0
- sentry 1.6.4