Skip to content

Commit

Permalink
Refactor OkHttp interceptors and turn them into Kotlin (#32)
Browse files Browse the repository at this point in the history
## Goal

Convert to Kotlin. I had to do a few things in order for this to work, and I'll point it out in the review via comments.

## Testing

Existing tests passes
  • Loading branch information
bidetofevil authored Oct 30, 2023
2 parents 8065b03 + c2a10a6 commit 8cf8db4
Show file tree
Hide file tree
Showing 19 changed files with 477 additions and 491 deletions.
6 changes: 3 additions & 3 deletions embrace-android-okhttp3/api/embrace-android-okhttp3.api
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
public class io/embrace/android/embracesdk/okhttp3/EmbraceCustomPathException : java/io/IOException {
public final class io/embrace/android/embracesdk/okhttp3/EmbraceCustomPathException : java/io/IOException {
public fun <init> (Ljava/lang/String;Ljava/lang/Throwable;)V
public fun getCustomPath ()Ljava/lang/String;
public final fun getCustomPath ()Ljava/lang/String;
}

public class io/embrace/android/embracesdk/okhttp3/EmbraceOkHttp3ApplicationInterceptor : okhttp3/Interceptor {
public final class io/embrace/android/embracesdk/okhttp3/EmbraceOkHttp3ApplicationInterceptor : okhttp3/Interceptor {
public fun <init> ()V
public fun intercept (Lokhttp3/Interceptor$Chain;)Lokhttp3/Response;
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.embrace.android.embracesdk.okhttp3

import io.embrace.android.embracesdk.InternalApi
import java.io.IOException

/**
* We use the EmbraceCustomPathException to capture the custom path added in the
* intercept chain process for client errors.
*/
@InternalApi
public class EmbraceCustomPathException(public val customPath: String, cause: Throwable?) : IOException(cause)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package io.embrace.android.embracesdk.okhttp3

import io.embrace.android.embracesdk.Embrace
import io.embrace.android.embracesdk.InternalApi
import io.embrace.android.embracesdk.internal.network.http.EmbraceHttpPathOverride
import io.embrace.android.embracesdk.network.EmbraceNetworkRequest
import io.embrace.android.embracesdk.network.http.HttpMethod
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import java.io.IOException

/**
* This interceptor will only intercept errors that client app experiences.
*
* We used OkHttp application interceptor in this case because this interceptor
* will be added first in the OkHttp3 interceptors stack. This allows us to catch network errors.
* OkHttp network interceptors are added almost at the end of stack, they are closer to "the wire"
* so they are not able to see network errors.
*
* We used the [EmbraceCustomPathException] to capture the custom path added in the interceptor
* chain process for client errors on requests to a generic URL like a GraphQL endpoint.
*/
@InternalApi
public class EmbraceOkHttp3ApplicationInterceptor internal constructor(
private val embrace: Embrace
) : Interceptor {

public constructor() : this(Embrace.getInstance())

@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val startTime = embrace.internalInterface.getSdkCurrentTime()
val request: Request = chain.request()
return try {
// we are not interested in response, just proceed
chain.proceed(request)
} catch (e: EmbraceCustomPathException) {
if (embrace.isStarted && !embrace.internalInterface.isInternalNetworkCaptureDisabled()) {
val urlString = EmbraceHttpPathOverride.getURLString(EmbraceOkHttp3PathOverrideRequest(request), e.customPath)
embrace.recordNetworkRequest(
EmbraceNetworkRequest.fromIncompleteRequest(
urlString,
HttpMethod.fromString(request.method),
startTime,
embrace.internalInterface.getSdkCurrentTime(),
causeName(e, UNKNOWN_EXCEPTION),
causeMessage(e, UNKNOWN_MESSAGE),
request.header(embrace.traceIdHeader),
if (embrace.internalInterface.isNetworkSpanForwardingEnabled()) request.header(TRACEPARENT_HEADER_NAME) else null,
null
)
)
}
throw e
} catch (e: Exception) {
// we are interested in errors.
if (embrace.isStarted && !embrace.internalInterface.isInternalNetworkCaptureDisabled()) {
val urlString = EmbraceHttpPathOverride.getURLString(EmbraceOkHttp3PathOverrideRequest(request))
val errorType = e.javaClass.canonicalName
val errorMessage = e.message
embrace.recordNetworkRequest(
EmbraceNetworkRequest.fromIncompleteRequest(
urlString,
HttpMethod.fromString(request.method),
startTime,
embrace.internalInterface.getSdkCurrentTime(),
errorType ?: UNKNOWN_EXCEPTION,
errorMessage ?: UNKNOWN_MESSAGE,
request.header(embrace.traceIdHeader),
if (embrace.internalInterface.isNetworkSpanForwardingEnabled()) request.header(TRACEPARENT_HEADER_NAME) else null,
null
)
)
}
throw e
}
}

internal companion object {
internal const val TRACEPARENT_HEADER_NAME = "traceparent"
internal const val UNKNOWN_EXCEPTION = "Unknown"
internal const val UNKNOWN_MESSAGE = "An error occurred during the execution of this network request"

/**
* Return the canonical name of the cause of a [Throwable]. Handles null elements throughout,
* including the throwable and its cause, in which case [defaultName] is returned
*/
internal fun causeName(throwable: Throwable?, defaultName: String = ""): String {
return throwable?.cause?.javaClass?.canonicalName ?: defaultName
}

/**
* Return the message of the cause of a [Throwable]. Handles null elements throughout,
* including the throwable and its cause, in which case [defaultMessage] is returned
*/
internal fun causeMessage(throwable: Throwable?, defaultMessage: String = ""): String {
return throwable?.cause?.message ?: defaultMessage
}
}
}
Loading

0 comments on commit 8cf8db4

Please sign in to comment.