ひだまりソケットは壊れない

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

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

*1:ページとしては存在するが、まだ記載されていない

*2:Application クラスが継承している Pipeline クラスが実装している