Как я могу переопределить logRequest/logResponse для регистрации пользовательского сообщения в журнале клиента Ktor?
В настоящее время реализация ведения журнала клиента 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, мне бы хотелось узнать, как изменить его поведение. Поскольку в Котлине все классы являются окончательными, если не открываются специально, я не знаю, как подойти к изменению
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))
}
Любая помощь будет признательна
2 ответа
Невозможно фактически переопределить частный метод в закрытом классе, но если вы просто хотите, чтобы ваше ведение журнала работало по-другому, вам лучше использовать собственный перехватчик того же этапа в конвейере:
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"
}
}
}
}
}
Вам также нужно добавить метод из класса Ktor Logger.kt в ваш класс с помощью HttpClient:
internal suspend inline fun ByteReadChannel.tryReadText(charset: Charset): String? = try {
readRemaining().readText(charset = charset)
} catch (cause: Throwable) {
null
}