Skip to content
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

feat: enable access to metrics for HTTP streams #86

Merged
merged 2 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changes/cfc58da7-d2c6-47d7-a40e-72893b49bca7.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"id": "cfc58da7-d2c6-47d7-a40e-72893b49bca7",
"type": "feature",
"description": "Enable access to metrics for HTTP streams",
"issues": [
"https://github.com/awslabs/smithy-kotlin/issues/893"
]
}
29 changes: 29 additions & 0 deletions aws-crt-kotlin/api/android/aws-crt-kotlin.api
Original file line number Diff line number Diff line change
Expand Up @@ -634,14 +634,43 @@ public abstract interface class aws/sdk/kotlin/crt/http/HttpStream : aws/sdk/kot
public abstract fun writeChunk ([BZ)V
}

public final class aws/sdk/kotlin/crt/http/HttpStreamMetrics {
public fun <init> (JJJJJJI)V
public final fun component1 ()J
public final fun component2 ()J
public final fun component3 ()J
public final fun component4 ()J
public final fun component5 ()J
public final fun component6 ()J
public final fun component7 ()I
public final fun copy (JJJJJJI)Laws/sdk/kotlin/crt/http/HttpStreamMetrics;
public static synthetic fun copy$default (Laws/sdk/kotlin/crt/http/HttpStreamMetrics;JJJJJJIILjava/lang/Object;)Laws/sdk/kotlin/crt/http/HttpStreamMetrics;
public fun equals (Ljava/lang/Object;)Z
public final fun getReceiveEndTimestampNs ()J
public final fun getReceiveStartTimestampNs ()J
public final fun getReceivingDurationNs ()J
public final fun getSendEndTimestampNs ()J
public final fun getSendStartTimestampNs ()J
public final fun getSendingDurationNs ()J
public final fun getStreamId ()I
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class aws/sdk/kotlin/crt/http/HttpStreamMetricsJVMKt {
public static final fun toKotlin (Lsoftware/amazon/awssdk/crt/http/HttpStreamMetrics;)Laws/sdk/kotlin/crt/http/HttpStreamMetrics;
}

public abstract interface class aws/sdk/kotlin/crt/http/HttpStreamResponseHandler {
public abstract fun onMetrics (Laws/sdk/kotlin/crt/http/HttpStream;Laws/sdk/kotlin/crt/http/HttpStreamMetrics;)V
public abstract fun onResponseBody (Laws/sdk/kotlin/crt/http/HttpStream;Laws/sdk/kotlin/crt/io/Buffer;)I
public abstract fun onResponseComplete (Laws/sdk/kotlin/crt/http/HttpStream;I)V
public abstract fun onResponseHeaders (Laws/sdk/kotlin/crt/http/HttpStream;IILjava/util/List;)V
public abstract fun onResponseHeadersDone (Laws/sdk/kotlin/crt/http/HttpStream;I)V
}

public final class aws/sdk/kotlin/crt/http/HttpStreamResponseHandler$DefaultImpls {
public static fun onMetrics (Laws/sdk/kotlin/crt/http/HttpStreamResponseHandler;Laws/sdk/kotlin/crt/http/HttpStream;Laws/sdk/kotlin/crt/http/HttpStreamMetrics;)V
public static fun onResponseBody (Laws/sdk/kotlin/crt/http/HttpStreamResponseHandler;Laws/sdk/kotlin/crt/http/HttpStream;Laws/sdk/kotlin/crt/io/Buffer;)I
public static fun onResponseHeadersDone (Laws/sdk/kotlin/crt/http/HttpStreamResponseHandler;Laws/sdk/kotlin/crt/http/HttpStream;I)V
}
Expand Down
29 changes: 29 additions & 0 deletions aws-crt-kotlin/api/jvm/aws-crt-kotlin.api
Original file line number Diff line number Diff line change
Expand Up @@ -634,14 +634,43 @@ public abstract interface class aws/sdk/kotlin/crt/http/HttpStream : aws/sdk/kot
public abstract fun writeChunk ([BZ)V
}

public final class aws/sdk/kotlin/crt/http/HttpStreamMetrics {
public fun <init> (JJJJJJI)V
public final fun component1 ()J
public final fun component2 ()J
public final fun component3 ()J
public final fun component4 ()J
public final fun component5 ()J
public final fun component6 ()J
public final fun component7 ()I
public final fun copy (JJJJJJI)Laws/sdk/kotlin/crt/http/HttpStreamMetrics;
public static synthetic fun copy$default (Laws/sdk/kotlin/crt/http/HttpStreamMetrics;JJJJJJIILjava/lang/Object;)Laws/sdk/kotlin/crt/http/HttpStreamMetrics;
public fun equals (Ljava/lang/Object;)Z
public final fun getReceiveEndTimestampNs ()J
public final fun getReceiveStartTimestampNs ()J
public final fun getReceivingDurationNs ()J
public final fun getSendEndTimestampNs ()J
public final fun getSendStartTimestampNs ()J
public final fun getSendingDurationNs ()J
public final fun getStreamId ()I
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class aws/sdk/kotlin/crt/http/HttpStreamMetricsJVMKt {
public static final fun toKotlin (Lsoftware/amazon/awssdk/crt/http/HttpStreamMetrics;)Laws/sdk/kotlin/crt/http/HttpStreamMetrics;
}

public abstract interface class aws/sdk/kotlin/crt/http/HttpStreamResponseHandler {
public abstract fun onMetrics (Laws/sdk/kotlin/crt/http/HttpStream;Laws/sdk/kotlin/crt/http/HttpStreamMetrics;)V
public abstract fun onResponseBody (Laws/sdk/kotlin/crt/http/HttpStream;Laws/sdk/kotlin/crt/io/Buffer;)I
public abstract fun onResponseComplete (Laws/sdk/kotlin/crt/http/HttpStream;I)V
public abstract fun onResponseHeaders (Laws/sdk/kotlin/crt/http/HttpStream;IILjava/util/List;)V
public abstract fun onResponseHeadersDone (Laws/sdk/kotlin/crt/http/HttpStream;I)V
}

public final class aws/sdk/kotlin/crt/http/HttpStreamResponseHandler$DefaultImpls {
public static fun onMetrics (Laws/sdk/kotlin/crt/http/HttpStreamResponseHandler;Laws/sdk/kotlin/crt/http/HttpStream;Laws/sdk/kotlin/crt/http/HttpStreamMetrics;)V
public static fun onResponseBody (Laws/sdk/kotlin/crt/http/HttpStreamResponseHandler;Laws/sdk/kotlin/crt/http/HttpStream;Laws/sdk/kotlin/crt/io/Buffer;)I
public static fun onResponseHeadersDone (Laws/sdk/kotlin/crt/http/HttpStreamResponseHandler;Laws/sdk/kotlin/crt/http/HttpStream;I)V
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package aws.sdk.kotlin.crt.http

public data class HttpStreamMetrics(
val sendStartTimestampNs: Long,
val sendEndTimestampNs: Long,
val sendingDurationNs: Long,
val receiveStartTimestampNs: Long,
val receiveEndTimestampNs: Long,
val receivingDurationNs: Long,
val streamId: Int,
)
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ public interface HttpStreamResponseHandler {
// window size through `Stream.incrementWindow()`?
bodyBytesIn.len

/**
* Called right before stream is complete, whether successful or unsuccessful.
* @param stream The HTTP stream to which the metrics apply
* @param metrics The [HttpStreamMetrics] containing metrics for the given stream
*/
public fun onMetrics(stream: HttpStream, metrics: HttpStreamMetrics) {
/* Optional callback, nothing to do by default */
}

/**
* Called from Native when the Response has completed.
* @param stream completed stream
Expand Down
29 changes: 18 additions & 11 deletions aws-crt-kotlin/jvm/src/aws/sdk/kotlin/crt/http/HttpRequestUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,56 +8,63 @@ package aws.sdk.kotlin.crt.http
import aws.sdk.kotlin.crt.io.MutableBuffer
import aws.sdk.kotlin.crt.io.byteArrayBuffer
import java.nio.ByteBuffer
import software.amazon.awssdk.crt.http.HttpHeader as HttpHeaderJni
import software.amazon.awssdk.crt.http.HttpRequest as HttpRequestJni
import software.amazon.awssdk.crt.http.HttpRequestBodyStream as HttpRequestBodyStreamJni
import software.amazon.awssdk.crt.http.HttpStream as HttpStreamJni
import software.amazon.awssdk.crt.http.HttpStreamMetrics as HttpStreamMetricsJni
import software.amazon.awssdk.crt.http.HttpStreamResponseHandler as HttpStreamResponseHandlerJni

/**
* Convert the KMP version of [HttpRequest] into the JNI equivalent
*/
internal fun HttpRequest.into(): HttpRequestJni {
val jniHeaders = headers.entries()
.map { entry ->
entry.value.map {
software.amazon.awssdk.crt.http.HttpHeader(entry.key, it)
}
entry.value.map { HttpHeaderJni(entry.key, it) }
}
.flatten()
.toTypedArray()

val bodyStream = body?.let { JniRequestBodyStream(it) }
return software.amazon.awssdk.crt.http.HttpRequest(method, encodedPath, jniHeaders, bodyStream)
return HttpRequestJni(method, encodedPath, jniHeaders, bodyStream)
}

internal fun HttpStreamResponseHandler.asJniStreamResponseHandler(): software.amazon.awssdk.crt.http.HttpStreamResponseHandler {
internal fun HttpStreamResponseHandler.asJniStreamResponseHandler(): HttpStreamResponseHandlerJni {
val handler = this
return object : software.amazon.awssdk.crt.http.HttpStreamResponseHandler {
return object : HttpStreamResponseHandlerJni {
override fun onResponseHeaders(
stream: software.amazon.awssdk.crt.http.HttpStream,
stream: HttpStreamJni,
statusCode: Int,
blockType: Int,
headers: Array<out software.amazon.awssdk.crt.http.HttpHeader>?,
headers: Array<out HttpHeaderJni>?,
) {
val ktHeaders = headers?.map { HttpHeader(it.name, it.value) }
val ktStream = HttpStreamJVM(stream)
handler.onResponseHeaders(ktStream, statusCode, blockType, ktHeaders)
}

override fun onResponseHeadersDone(stream: software.amazon.awssdk.crt.http.HttpStream, blockType: Int) {
override fun onResponseHeadersDone(stream: HttpStreamJni, blockType: Int) {
val ktStream = HttpStreamJVM(stream)
handler.onResponseHeadersDone(ktStream, blockType)
}

override fun onResponseBody(stream: software.amazon.awssdk.crt.http.HttpStream, bodyBytesIn: ByteArray?): Int {
override fun onResponseBody(stream: HttpStreamJni, bodyBytesIn: ByteArray?): Int {
if (bodyBytesIn == null) return 0
val ktStream = HttpStreamJVM(stream)
val buffer = byteArrayBuffer(bodyBytesIn)
return handler.onResponseBody(ktStream, buffer)
}

override fun onResponseComplete(stream: software.amazon.awssdk.crt.http.HttpStream, errorCode: Int) {
override fun onResponseComplete(stream: HttpStreamJni, errorCode: Int) {
val ktStream = HttpStreamJVM(stream)
handler.onResponseComplete(ktStream, errorCode)
}

override fun onMetrics(stream: HttpStreamJni, metrics: HttpStreamMetricsJni) {
val ktStream = HttpStreamJVM(stream)
handler.onMetrics(ktStream, metrics.toKotlin())
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package aws.sdk.kotlin.crt.http

/**
* Convert a CRT JNI metrics object into a Kotlin-native one
*/
public fun software.amazon.awssdk.crt.http.HttpStreamMetrics.toKotlin(): HttpStreamMetrics =
HttpStreamMetrics(
sendStartTimestampNs = this.sendStartTimestampNs,
sendEndTimestampNs = this.sendEndTimestampNs,
sendingDurationNs = this.sendingDurationNs,
receiveStartTimestampNs = this.receiveStartTimestampNs,
receiveEndTimestampNs = this.receiveEndTimestampNs,
receivingDurationNs = this.receivingDurationNs,
streamId = this.streamId,
)
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
buildscript {
repositories {
mavenCentral()
mavenLocal()
}

dependencies {
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
kotlin-version = "1.9.21"

# libs
crt-java-version = "0.29.1"
crt-java-version = "0.29.6"
coroutines-version = "1.7.3"

# testing
Expand Down
Loading