- Web Engineer
- アウトバウンド営業
- Webエンジニア(経験者)
- Other occupations (19)
- Development
- Business
Kotlin Coroutines withContextを使ってもStackTraceを諦めたくない【株式会社ライトコード】
はじめに
本記事は、以前の記事
Kotlin Coroutines withContextを使っているとStackTraceを用いた不具合調査が辛いのをどうにかしたい
の解決提案編となります。
どんな問題だったか
Koltin CouroitnesのwithContextを利用してスレッド変更すると
StackTraceが途切れてしまい不具合発生時の処理履歴が追えなくなる
という問題でした。
詳しくは前回の記事を確認してください。
解決案1:withContextごとに、例外ラッパークラスにStackTrace情報を詰め込む(問題あり…)
↓まずは、例外ラッパークラスを作成。
/*
* Exceptionをラップするためのクラス
*/
class WrappedException(
message: String,
cause: Exception
) : Exception(message, cause) {
/**
* 例外の根本的な原因を取得するプロパティ
*
* このプロパティは、WrappedExceptionがラップしている例外の根本的な原因を返す
* もしWrappedExceptionがラップしている例外が別のWrappedExceptionであれば、その根本的な原因を再帰的に取得
*/
val rootCause: Throwable?
get() = cause?.let {
if (it is WrappedException) {
it.rootCause
} else {
it
}
}
}↓次に、独自のwithContextを作成
/*
* withContextを使用して、例外をラップするための関数
*
* @param context CoroutineContext
* @param block suspend CoroutineScope.() -> T
* @return T
*
* 呼び出し元のメソッド名と行番号を取得し、例外が発生した場合にその情報を含む[WrappedException]を投げる。
*/
suspend fun withContextWrapException(
context: CoroutineContext,
block: suspend CoroutineScope.() -> T,
): T {
val throwable = Throwable()
return withContext(context) {
try {
block()
} catch (e: CancellationException) {
// CancellationExceptionはそのまま投げる(suspend中断例外の伝播のため)
throw e
} catch (e: Exception) {
val callerStackTraceElement = throwable.stackTrace[1] // withContextWrapExceptionを呼び出しているメソッド
val callerOfCallerStackTraceElement = throwable.stackTrace[2] // 「withContextWrapExceptionを呼び出しているメソッド」を呼び出しているメソッド
val callerInfo =
"(${callerOfCallerStackTraceElement.fileName}:${callerOfCallerStackTraceElement.lineNumber}→${callerStackTraceElement.fileName}:${callerStackTraceElement.lineNumber})"
throw WrappedException(callerInfo, e)
}
}
}↓あとは、withContextの代わりに使うだけ。
// 適当なRpository
class HogeRepository(
private val dispatcherIO: CoroutineDispatcher = Dispatchers.IO
) {
suspend fun getHoge(): String = withContextWrapException(dispatcherIO) {
throw RuntimeException("適当な例外")
}
}↓ViewModelから呼び出すと
// 適当なViewModelから呼び出す
class MainViewModel(
private val repository: HogeRepository = HogeRepository()
) : ViewModel() {
fun onClickButton() {
viewModelScope.launch {
try {
hogeRepository.getHoge()
} catch (e: CancellationException) {
throw e // Jobキャンセル例外はキャッチしたらダメです
} catch (e: Exception) {
Log.e("hoge", "onClickButton", e)
_errorMessage.update { e.stackTraceToString() }
}
}
}
}↓以下のStackTraceが出力されます。※行数ズレてるのは気にしないでください。
これなら、どれだけスレッド変更しても大丈夫です
…
記事の続きは下のURLをクリック!
https://rightcode.co.jp/blogs/53715
エンジニア積極採用中です!
現在、WEBエンジニア、モバイルエンジニア、デザイナー、営業などを積極採用中です!
採用ページはこちら:https://rightcode.co.jp/recruit
社員の声や社風などを知りたい方はこちら:https://rightcode.co.jp/blogs?category=life
フリーランスエンジニア大募集中!
現在、「WEBエンジニア」「フロントエンジニア」「データサイエンティスト」など、様々な職種のフリーランスエンジニア様を募集中です。まずは以下よりお気軽にご応募ください!
採用ページはこちら:https://itanken.com/register
社長と一杯飲みながらお話しませんか?(転職者向け)
特設ページはこちら: https://rightcode.co.jp/gohan-sake-president-talk
もっとワクワクしたいあなたへ
現在、ライトコードでは「WEBエンジニア」「モバイルエンジニア」「ゲームエンジニア」、「デザイナー」「WEBディレクター」「営業」などを積極採用中です!
ライトコードは技術力に定評のある受託開発をメインにしているIT企業です。
有名WEBサービスやアプリの受託開発などの企画、開発案件が目白押しの状況です。
- もっと大きなことに挑戦したい!
- エンジニアとしてもっと成長したい!
- モダンな技術に触れたい!
現状に満足していない方は、まずは、エンジニアとしても第一線を走り続ける弊社代表と気軽にお話してみませんか?
ネット上では、ちょっとユルそうな会社に感じると思いますが(笑)、
実は技術力に定評があり、沢山の実績を残している会社ということをお伝えしたいと思っております。
- ライトコードの魅力を知っていただきたい!
- 社風や文化なども知っていただきたい!
- 技術に対して熱意のある方に入社していただきたい!
一度、【Wantedly内の弊社ページ】や【コーポレートサイト】をのぞいてみてください。
Wantedly:https://www.wantedly.com/companies/rightcode
コーポレート:https://rightcode.co.jp/