如何在Ktor客户端日志中覆盖logRequest/logResponse以记录自定义消息



目前,ktor客户端日志记录实现如下,它按预期工作,但不是我想要的。


public class Logging(
public val logger: Logger,
public var level: LogLevel,
public var filters: List<(HttpRequestBuilder) -> Boolean> = emptyList()
)
....
private suspend fun logRequest(request: HttpRequestBuilder): OutgoingContent? {
if (level.info) {
logger.log("REQUEST: ${Url(request.url)}")
logger.log("METHOD: ${request.method}")
}
val content = request.body as OutgoingContent
if (level.headers) {
logger.log("COMMON HEADERS")
logHeaders(request.headers.entries())
logger.log("CONTENT HEADERS")
logHeaders(content.headers.entries())
}
return if (level.body) {
logRequestBody(content)
} else null
}

上面在查看日志时创建了一个噩梦,因为它记录在每一行中。由于我是Kotlin和Ktor的初学者,我很想知道如何改变这种行为。由于在Kotlin中,除非专门打开,否则所有类都是final,所以我不知道如何修改logRequest函数的行为。我理想中想要实现的是下面的例子。

....
private suspend fun logRequest(request: HttpRequestBuilder): OutgoingContent? {
...
if (level.body) {
val content = request.body as OutgoingContent
return logger.log(value("url", Url(request.url)),
value("method", request.method),
value("body", content))

}

任何帮助都将感谢

没有办法在非开放类中实际覆盖私有方法,但如果你只是想让日志记录以不同的方式工作,那么最好在管道中使用相同阶段的自定义拦截器:

val client = HttpClient(CIO) {
install("RequestLogging") {
sendPipeline.intercept(HttpSendPipeline.Monitoring) {
logger.info(
"Request: {} {} {} {}",
context.method,
Url(context.url),
context.headers.entries(),
context.body
)
}
}
}
runBlocking {
client.get<String>("https://google.com")
}

这将生成您想要的日志记录。当然,要正确记录POST,您需要做一些额外的工作。

也许这对某人有用:

HttpClient() {
install("RequestLogging") {
responsePipeline.intercept(HttpResponsePipeline.After) {
val request = context.request
val response = context.response
kermit.d(tag = "Network") {
"${request.method} ${request.url} ${response.status}"
}
GlobalScope.launch(Dispatchers.Unconfined) {
val responseBody =
response.content.tryReadText(response.contentType()?.charset() ?: Charsets.UTF_8)
?: "[response body omitted]"
kermit.d(tag = "Network") {
"${request.method} ${request.url} ${response.status}nBODY START" +
"n$responseBody" +
"nBODY END"
}
}
}
}
}

您还需要使用HttpClient:将Ktor Logger.kt类中的一个方法添加到您的calss中

internal suspend inline fun ByteReadChannel.tryReadText(charset: Charset): String? = try {
readRemaining().readText(charset = charset)
} catch (cause: Throwable) {
null
}

最新更新