-
Notifications
You must be signed in to change notification settings - Fork 75
RUM-12635: RUM support for Cronet #3029
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feature/cronet
Are you sure you want to change the base?
Conversation
0a842f7 to
ec8f689
Compare
This comment has been minimized.
This comment has been minimized.
ec8f689 to
a111d25
Compare
ambushwork
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just finish the review of the half, will continue on next week.
| * Represents information about an HTTP request. | ||
| * Isolates specific library's details from the Datadog SDK. | ||
| */ | ||
| interface RequestInfo { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: should this be put inside internal module instead of core?
|
|
||
| /** | ||
| * Creates a new builder with Datadog instrumentation. | ||
| * @param context the Android context |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nip: should specify as application context
|
|
||
| // endregion | ||
| companion object { | ||
| // Exception thrown only for wrong arguments, buy those ones is correct |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // Exception thrown only for wrong arguments, buy those ones is correct | |
| // Exception thrown only for wrong arguments, but those ones are correct |
| internal val networkLayerName: String, | ||
| internal val rumResourceAttributesProvider: RumResourceAttributesProvider | ||
| ) { | ||
| private val sdkCoreReference = SdkReference(sdkInstanceName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you consider to add integration test for cronet <-> rum resoureces?
0xnm
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went only through the production files so far, didn't cover tests
| val headers: Map<String, List<String>> | ||
| val contentType: String? | ||
| fun contentLength(com.datadog.android.api.InternalLogger): Long? | ||
| fun headerValue(String): String? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strictly speaking, HTTP standard allows multiple occurrences of the same header, so return type should be List<String>, this can be seen in OkHttp API:
/** Returns an immutable list of the header values for `name`. */
fun values(name: String): List<String> {
| * @return the length of the content in bytes, or null if the content length is unavailable. | ||
| * @throws IOException if an error occurs while calculating the content length. | ||
| */ | ||
| @Throws(IOException::class) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we throw/rethrow anything?
| companion object { | ||
| fun assertThat(info: RequestInfo) = RequestInfoAssertions(info) | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| } | |
| } | |
|
|
||
| import org.assertj.core.api.Assertions | ||
|
|
||
| class RequestInfoAssertions private constructor(private val info: RequestInfo) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| class RequestInfoAssertions private constructor(private val info: RequestInfo) { | |
| class RequestInfoAssert private constructor(private val info: RequestInfo) { |
also it is worth to subclass AbstractObjectAssert<RequestInfoAssert, RequestInfo>
| request: RequestInfo, | ||
| response: ResponseInfo?, | ||
| throwable: Throwable? | ||
| ): Map<String, Any?> = emptyMap() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: default return value is not needed here
| ) : RequestFinishedInfo.Listener(executor) { | ||
|
|
||
| override fun onRequestFinished(finishedInfo: RequestFinishedInfo) { | ||
| val requestInfo = finishedInfo.annotations?.firstOrNull { it is RequestInfo } as? RequestInfo |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor
| val requestInfo = finishedInfo.annotations?.firstOrNull { it is RequestInfo } as? RequestInfo | |
| val requestInfo = finishedInfo.annotations?.filterIsInstance<RequestInfo>()?.firstOrNull() |
| } | ||
|
|
||
| val downloadStartMs = metrics.responseStart - metrics.requestStart | ||
| val downloadDurationMs = metrics.requestEnd - metrics.responseStart |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably a typo here
| val downloadDurationMs = metrics.requestEnd - metrics.responseStart | |
| val downloadDurationMs = metrics. responseEnd - metrics.responseStart |
| return if (thisTime == null || otherTime == null) 0L else thisTime - otherTime | ||
| } | ||
|
|
||
| private fun Long.toNanos(): Long = TimeUnit.MILLISECONDS.toNanos(this) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| private fun Long.toNanos(): Long = TimeUnit.MILLISECONDS.toNanos(this) | |
| private fun Long.millisToNanos(): Long = TimeUnit.MILLISECONDS.toNanos(this) |
| internal val url: String, | ||
| internal val delegate: UrlRequest.Builder, | ||
| internal val rumResourceInstrumentation: RumResourceInstrumentation | ||
| ) : UrlRequest.Builder() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ) : UrlRequest.Builder() { | |
| ) : UrlRequest.Builder() by delegate { |
| ) | ||
|
|
||
| addRequestAnnotation(requestInfo) | ||
| addRequestAnnotation(requestInfo.buildResourceId(generateUuid = true)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we just add it as a part of CronetRequestInfo?
| } | ||
|
|
||
| @Test | ||
| fun `M call delegate first THEN deprecated W onProvideAttributes { RequestInfo }`( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does THEN deprecated mean here?
| internal companion object { | ||
|
|
||
| // We need to limit this value as the body will be loaded in memory | ||
| private const val MAX_BODY_PEEK: Long = 32 * 1024L * 1024L |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it will be nice to add unit (bytes) in the name
| } | ||
|
|
||
| @Test | ||
| fun `M return null W contentLength() { upload data provider length is unknown }`() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure the name of this function corresponds the body, upload data provider is not unknown, it is -1, and the return value is not null, it is -1.
| override val method: String get() = request.method | ||
|
|
||
| override fun <T> tag(type: Class<out T>): T? = request.tag(type) | ||
| override fun contentLength(): Long = request.body?.contentLength() ?: 0L |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question, CronetRequestInfo has Long? as return value here, but OkHttpRequestInfo return 0 as default, is that expected?
| @@ -0,0 +1,69 @@ | |||
| package com.datadog.android.okhttp.internal | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor: Missing copyright
| @@ -0,0 +1,127 @@ | |||
| package com.datadog.android.cronet.internal | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor: Missing copyright
| import com.datadog.android.okhttp.internal.rum.buildResourceId | ||
| import com.datadog.android.okhttp.internal.buildResourceId | ||
| import com.datadog.android.okhttp.utils.config.DatadogSingletonTestConfiguration | ||
| import com.datadog.android.rum.resource.buildResourceId |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how does this import work with the other buildResourceId import?
What does this PR do?
This is a draft PR. work in progress
RumResourceInstrumentation, but neitherDatadogInterceptornorTracingInterceptorare using it.Review checklist (to be filled by reviewers)