Skip to content

Commit

Permalink
Merge pull request #6 from wireapp/staging
Browse files Browse the repository at this point in the history
0.2.4
LukasForst authored Oct 9, 2020

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents 1943b27 + a0040f5 commit 75a55e3
Showing 3 changed files with 82 additions and 19 deletions.
12 changes: 3 additions & 9 deletions src/main/kotlin/com/wire/bots/polls/setup/HttpClient.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.wire.bots.polls.setup

import com.wire.bots.polls.utils.ClientRequestMetric
import com.wire.bots.polls.utils.createLogger
import com.wire.bots.polls.utils.httpCall
import io.ktor.client.HttpClient
@@ -9,7 +10,6 @@ import io.ktor.client.features.json.JsonFeature
import io.ktor.client.features.logging.LogLevel
import io.ktor.client.features.logging.Logger
import io.ktor.client.features.logging.Logging
import io.ktor.client.features.observer.ResponseObserver
import io.micrometer.core.instrument.MeterRegistry


@@ -22,14 +22,8 @@ fun createHttpClient(meterRegistry: MeterRegistry) =
serializer = JacksonSerializer()
}

// TODO check https://github.com/ktorio/ktor/issues/1813
@Suppress("ConstantConditionIf") // temporary disabled until https://github.com/ktorio/ktor/issues/1813 is resolved
if (false) {
install(ResponseObserver) {
onResponse {
meterRegistry.httpCall(it)
}
}
install(ClientRequestMetric) {
onResponse { meterRegistry.httpCall(it) }
}

install(Logging) {
72 changes: 72 additions & 0 deletions src/main/kotlin/com/wire/bots/polls/utils/ClientRequestMetric.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.wire.bots.polls.utils

import io.ktor.client.HttpClient
import io.ktor.client.features.HttpClientFeature
import io.ktor.client.statement.HttpReceivePipeline
import io.ktor.client.statement.HttpResponse
import io.ktor.client.statement.request
import io.ktor.util.AttributeKey
import mu.KLogging

/**
* [ClientRequestMetric] callback.
*/
typealias RequestMetricHandler = suspend (RequestMetric) -> Unit


/**
* Enables callback after HttpClient sends a request with [RequestMetric].
*/
class ClientRequestMetric(private val metricHandler: RequestMetricHandler) {

class Config {
internal var metricHandler: RequestMetricHandler = {}

/**
* Set [RequestMetricHandler] called at the end of the request.
*/
fun onResponse(block: RequestMetricHandler) {
metricHandler = block
}
}

companion object Feature : HttpClientFeature<Config, ClientRequestMetric>, KLogging() {

override val key: AttributeKey<ClientRequestMetric> =
AttributeKey("ClientRequestMetric")

override fun prepare(block: Config.() -> Unit) =
ClientRequestMetric(Config().apply(block).metricHandler)

override fun install(feature: ClientRequestMetric, scope: HttpClient) {
// synchronous response pipeline hook
// instead of ResponseObserver - which spawns a new coroutine
scope.receivePipeline.intercept(HttpReceivePipeline.After) { response ->
// WARNING: Do not consume HttpResponse.content here,
// or you will corrupt the client response.
runCatching { feature.metricHandler(response.toRequestMetric()) }
.onFailure { logger.error(it) { "Error during metering!" } }
}
}

// does not touch the content
private fun HttpResponse.toRequestMetric() = RequestMetric(
requestTime = requestTime.timestamp,
responseTime = responseTime.timestamp,
method = request.method.value,
url = request.url.toString(),
responseCode = status.value
)
}
}


data class RequestMetric(
// number of epoch milliseconds
val requestTime: Long,
val responseTime: Long,
val method: String,
val url: String,
val responseCode: Int
)

17 changes: 7 additions & 10 deletions src/main/kotlin/com/wire/bots/polls/utils/PrometheusExtensions.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.wire.bots.polls.utils

import io.ktor.client.statement.HttpResponse
import io.ktor.client.statement.request
import io.micrometer.core.instrument.MeterRegistry
import io.micrometer.core.instrument.Tag
import java.util.concurrent.TimeUnit
@@ -18,18 +16,17 @@ fun MeterRegistry.countException(exception: Throwable, additionalTags: Map<Strin
counter("exceptions", tags).increment()
}


/**
* Register http call.
*
*/
fun MeterRegistry.httpCall(response: HttpResponse) {
val startTime = response.requestTime.timestamp
val endTime = response.responseTime.timestamp

val duration = endTime - startTime
fun MeterRegistry.httpCall(requestMetric: RequestMetric) {
val duration = requestMetric.responseTime - requestMetric.requestTime
val tags = mapOf(
"method" to response.request.method.value,
"url" to response.request.url.toString(),
"response_code" to response.status.value.toString()
"method" to requestMetric.method,
"url" to requestMetric.url,
"response_code" to requestMetric.responseCode.toString()
).toTags()

timer("http_calls", tags).record(duration, TimeUnit.MILLISECONDS)

0 comments on commit 75a55e3

Please sign in to comment.