I am using Retrofit, OkHttp, Kotlin coroutines to make HTTP requests.
When the server returns an unsuccessful result (e.g., 404), I throw a custom exception, which is a subtype of IOException
.
The resulted stack trace does not point to code that initially made a request.
The resulted stack trace only points to interceptor code, which doesn’t help me identify the original call site.
Question:
How can I ensure that when I throw a custom exception (a subtype of IOException
), the stack trace points to code that initially made a request (e.g. catApi.callThatReturns404()
)?
Constraints:
- Wrapping every remote API call with try/catch is not an option because the issue is global, and I don’t want to wrap it in hundreds of places.
- Simply logging inside the interceptor is not sufficient since I need the full stack trace.
- Avoiding the use of the custom exception is not an option, as it holds information.
- Solution should also work in production code. Not only when some debug tools are turned on
Example code
fun main(): Unit = runBlocking {
val api = createCatApi()
api.callThatReturns404()
}
private fun createCatApi(): CatApi {
val url = "https://cat-fact.herokuapp.com/"
val httpClient = OkHttpClient.Builder()
.addInterceptor { chain ->
val response = chain.proceed(chain.request())
if (!response.isSuccessful) {
throw SubTypeOfIOException(response)
}
response
}
.build()
val retrofit = Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(JacksonConverterFactory.create(ObjectMapper().registerKotlinModule()))
.client(httpClient)
.build()
return retrofit.create<CatApi>()
}
interface CatApi {
@GET("factss")
suspend fun callThatReturns404(): Collection<Any>
}
Stack trace, when SubTypeOfIOException
is thrown
Exception in thread "main" com.SubTypeOfIOException: 404
at com.MainKt$createCatApi$$inlined$-addInterceptor$1.intercept(OkHttpClient.kt:1082)
What I want
Exception in thread "main" com.retrofit_test.SubTypeOfIOException: 404
at com.retrofit_test.Main.main(Main.kt:15)
Caused by: com.SubTypeOfIOException: 404
at com.MainKt$createCatApi$$inlined$-addInterceptor$1.intercept(OkHttpClient.kt:1082)
Interesting thing: when I call such code from tests and throw IOException
, the stack trace contains information I want. If in tests I throw a subtype of IOException
, the stack trace does not contain such information
Versions:
- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0
- com.squareup.retrofit2:retrofit:2.11.0
- com.squareup.okhttp3:okhttp:4.12.0