Skip to content

Instantly share code, notes, and snippets.

@matale
Created April 7, 2023 03:23
Show Gist options
  • Save matale/8026e473f63ef381d8c6177e41a816ea to your computer and use it in GitHub Desktop.
Save matale/8026e473f63ef381d8c6177e41a816ea to your computer and use it in GitHub Desktop.
Crashlytics Logging Interceptor for OkHttp when you cant figure out where that error is comming from
import com.google.firebase.crashlytics.FirebaseCrashlytics
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import okio.Buffer
import java.io.IOException
/*
Log HTTP requests to Crashlytics.
Note you need to be mindful of logging sensitive info.
These logs will appear in the details of the next fatal or non fatal crash on Firebase -> Crashlytics.
Logs are not sent unless a fatal crash happens or you record a non-fatal exception with
FirebaseCrashlytics.getInstance().recordException(throwable)
Remember that Crashlytics will only include the last 64kB of log messages with each crash so logging too much might be counter productive its best to be selective with what is logged.
Usage.
Wherever you are creating your OkHttpClient add this as an interceptor. e.g.
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(CrashlyticsOkHttpInterceptor())
.build()
*/
class CrashlyticsOkHttpInterceptor : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val request: Request = chain.request()
val response: Response = chain.proceed(request)
val code = response.code
//Here we are only logging full req/response if the response was above HTTP code 200 (Success)
if (code > 200) {
val requestBuffer = Buffer()
request.body?.writeTo(requestBuffer)
val requestHeaders = request.headers.toString()
val responseBody = response.peekBody(Long.MAX_VALUE).string()
val responseHeaders = response.headers.toString()
val requestUrl = response.request.url.toString()
val msg = "code: $code url:$requestUrl reqH:$requestHeaders reqB:${requestBuffer.readUtf8()} resH:$responseHeaders resB:$responseBody"
FirebaseCrashlytics.getInstance().log(msg)
} else {
//If its HTTP 200 or less just log the request URL. To reduce size of logs.
val requestUrl = response.request.url.toString()
val msg = "code: $code url:$requestUrl"
FirebaseCrashlytics.getInstance().log(msg)
}
/*
Optionally record a non-fatal exception for some http codes, this will cause the logs to actually be sent.
Without this the logs will only be sent if the app crashes somewhere else after this request.
You can see full list of HTTP codes at https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
*/
if (code == 500) {
FirebaseCrashlytics.getInstance().recordException(Throwable("Http logging code: $code"))
}
return response
}
}
@matale
Copy link
Author

matale commented Apr 15, 2023

I have noticed that this has a problem if you are also using the same okHttpClient to download/upload binaries/files, it will attempt to log the entire binary content which can cause out of memory errors, one fix is to use separate okHttpClient for the downloading/uploading of files or exclude logging in this interceptor if the body does not contain text you can see an example of this here https://github.com/square/okhttp/blob/master/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/HttpLoggingInterceptor.kt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment