I'm running a ktor server as the primary api for an application I'm working on and one of the endpoints delivers big files to some clients. I would like to implement some form of logging of how many bytes of the file were sent in a given request and have not been able to figure out an accurate way of doing so.
I hope I haven't missed anything totally obvious ^^
I have for example tried to extend the LocalFileContent
class and added a coroutine job to log the traffic like this
private fun listenChannel(channel: ByteReadChannel) {
scope.launch {
while (!channel.isClosedForRead)
delay(500L)
addTraffic(device, channel.totalBytesRead)
println("Adding ${channel.totalBytesRead} bytes of traffic to the buffer.")
listenJob.complete()
}
}
Which kind of works but sometimes ends up with wildly unrealistic numbers and even more so when running behind a reverse proxy for some reason.
You can write a custom plugin to log how big the to-be-responded body is in bytes.
fun Application.installLogger() {
sendPipeline.intercept(ApplicationSendPipeline.After) { body ->
val content = when (body) {
is OutgoingContent.ReadChannelContent -> {
object : OutgoingContent.ReadChannelContent() {
override val contentLength = body.contentLength
override val contentType = body.contentType
override fun readFrom(): ByteReadChannel {
return GlobalScope.writer {
val copied = body.readFrom().copyTo(channel)
println("Returned $copied bytes")
}.channel
}
}
}
is OutgoingContent.ByteArrayContent -> {
println("Returned ${body.bytes().size} bytes")
body
}
else -> body
}
proceedWith(content)
}
}
fun main() {
embeddedServer(Netty, port = 3000) {
install(PartialContent)
installLogger()
routing {
get("/file") {
call.respondFile(File("file.jpg"))
}
}
}.start(wait = true)
}