From dc0d311ea746170e7ec1b7355c6ffe419b43e9dc Mon Sep 17 00:00:00 2001 From: Mariia Skripchenko <61115099+marychatte@users.noreply.github.com> Date: Thu, 4 Apr 2024 08:36:36 +0200 Subject: [PATCH] KTOR-6839 Fix double logging response in CallLogging (#4016) (cherry picked from commit 3a605a6abd0394d764c0e20eb78b3bd958a9f40f) --- .../ktor/server/plugins/callloging/MDCHook.kt | 6 ++++ .../plugins/callloging/CallLoggingTest.kt | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/ktor-server/ktor-server-plugins/ktor-server-call-logging/jvm/src/io/ktor/server/plugins/callloging/MDCHook.kt b/ktor-server/ktor-server-plugins/ktor-server-call-logging/jvm/src/io/ktor/server/plugins/callloging/MDCHook.kt index d4edd0ee38..82e48a3695 100644 --- a/ktor-server/ktor-server-plugins/ktor-server-call-logging/jvm/src/io/ktor/server/plugins/callloging/MDCHook.kt +++ b/ktor-server/ktor-server-plugins/ktor-server-call-logging/jvm/src/io/ktor/server/plugins/callloging/MDCHook.kt @@ -6,6 +6,7 @@ package io.ktor.server.plugins.callloging import io.ktor.server.application.* import io.ktor.server.response.* +import io.ktor.util.* import io.ktor.util.pipeline.* internal fun MDCHook(phase: PipelinePhase) = object : Hook Unit) -> Unit> { @@ -25,8 +26,13 @@ internal fun MDCHook(phase: PipelinePhase) = object : Hook Unit> { override fun install(pipeline: ApplicationCallPipeline, handler: suspend (ApplicationCall) -> Unit) { pipeline.sendPipeline.intercept(ApplicationSendPipeline.Engine) { + if (call.attributes.contains(responseSentMarker)) return@intercept + + call.attributes.put(responseSentMarker, Unit) proceed() handler(call) } } } + +private val responseSentMarker = AttributeKey("ResponseSentTriggered") diff --git a/ktor-server/ktor-server-plugins/ktor-server-call-logging/jvm/test/io/ktor/server/plugins/callloging/CallLoggingTest.kt b/ktor-server/ktor-server-plugins/ktor-server-call-logging/jvm/test/io/ktor/server/plugins/callloging/CallLoggingTest.kt index 68eb9eae9f..9067139a6c 100644 --- a/ktor-server/ktor-server-plugins/ktor-server-call-logging/jvm/test/io/ktor/server/plugins/callloging/CallLoggingTest.kt +++ b/ktor-server/ktor-server-plugins/ktor-server-call-logging/jvm/test/io/ktor/server/plugins/callloging/CallLoggingTest.kt @@ -568,6 +568,35 @@ class CallLoggingTest { assertContains(messages, "INFO: /without [hardcoded=1]") } + @Test + fun `no double logging when with Status Pages`() = testApplication { + environment { + log = logger + } + application { + install(CallLogging) { + format { it.request.uri } + } + install(StatusPages) { + status(HttpStatusCode.BadRequest) { call, _ -> + call.respond("From StatusPages") + } + } + } + routing { + get { + call.respond(HttpStatusCode.BadRequest) + } + } + + client.get("/").apply { + assertEquals(HttpStatusCode.OK, status) + assertEquals("From StatusPages", bodyAsText()) + } + + assertEquals(1, messages.count { it == "INFO: /" }) + } + private fun green(value: Any): String = colored(value, Ansi.Color.GREEN) private fun red(value: Any): String = colored(value, Ansi.Color.RED) private fun cyan(value: Any): String = colored(value, Ansi.Color.CYAN)