module {
// install CallId...
install(DoubleReceive) {
receiveEntireContent = true
}
install(Logging) {
logRequests = true
logResponses = true
logFullUrl = true
logBody = true
logHeaders = true
filterPath("/api", "/version", "/openapi")
}
}You can select which calls you want to log with filter and filterPath configuration functions.
Logging of request/response payloads requires installation of DoubleReceive plugin with receiveEntireContent = true.
|
Warning
|
Payloads may contain sensitive data not suitable for logging. That’s why this is disabled by default. |
Example
2019-12-03 11:21:27.086 INFO [atcher-worker-5] (Logging.kt:87) : Received request:
GET http://localhost:8080/api/entities/102 HTTP/1.1
Host: localhost:8080
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.9 (Java/11.0.4)
Accept-Encoding: gzip,deflate
2019-12-03 11:21:27.265 INFO [atcher-worker-5] (Logging.kt:81) : 253 ms - 404 - GET http://localhost:8080/api/entities/102
2019-12-03 11:21:27.269 INFO [atcher-worker-5] (Logging.kt:104) : Sent response:
HTTP/1.1 404 Not Found
X-Request-ID: dc3d3804-23b5-4b9f-a8d4-714eec6b4c55
Date: Tue, 03 Dec 2019 10:21:27 GMT
Server: kotlin-template/0.1-SNAPSHOT
Content-Length: 271
Content-Type: application/json; charset=UTF-8
Connection: keep-alive
{"status":404,"type":"my.app.exceptions.ItemNotFoundException","title":"Not Found","detail":"Could not find entity id=102","instance":"dc3d3804-23b5-4b9f-a8d4-714eec6b4c55","path":"/api/entities/102","timestamp":"2019-12-03T11:21:27.186445+01:00"}
Plugin is fully open for customizations. You can base on it your own logging plugin, which you are encouraged to do.
For example with logback’s logstash encoder you can enhance your log JSONs like that:
override fun logPerformance(call: ApplicationCall) {
val duration = System.currentTimeMillis() - call.attributes[startTimeKey]
val route = call.attributes.getOrNull(routeKey)?.parent.toString()
val method = call.request.httpMethod.value
val requestURI = if (logFullUrl) call.request.origin.uri else call.request.path()
val requestInfo = mapOf(
"method" to method,
"protocol" to call.request.origin.version,
"url" to call.request.origin.run { "$scheme://$host:$port$requestURI" },
"api" to "$method $route",
"route" to route,
"remoteHost" to call.request.origin.remoteHost,
"contentType" to call.request.contentType().toString(),
"contentLength" to call.request.headers[HttpHeaders.ContentLength]?.toInt()
)
val responseInfo = mapOf(
"status" to call.response.status()?.value,
"contentType" to call.response.headers[HttpHeaders.ContentType],
"contentLength" to call.response.headers[HttpHeaders.ContentLength]?.toInt()
)
val additionalInfo = mapOf(
"request" to requestInfo,
"response" to responseInfo
)
log.info("{} ms - {} - {} {}", value("duration", duration), responseInfo["status"], method, requestInfo["url"], appendEntries(additionalInfo))
}{
"@timestamp": "2019-11-28T13:24:47.832+01:00",
"@version": "1",
"message": "3 ms - 200 - GET http://localhost:8080/api/entities",
"logger_name": "koriit.kotlin.app.Logging",
"thread_name": "worker-4",
"level": "INFO",
"level_value": 20000,
"correlationId": "db4f0ccb-0ba8-45f8-a21b-6adb83c6bd86",
"duration": 3,
"request": {
"method": "GET",
"protocol": "HTTP/1.1",
"url": "http://localhost:8080/api/entities",
"api": "GET /api/entities",
"route": "/api/entities",
"remoteHost": "unknown",
"contentType": "*/*",
"contentLength": null
},
"response": {
"status": 200,
"contentType": "application/json; charset=UTF-8",
"contentLength": 5606
}
}