タイトルについてまず捕捉する。
そもそもログインしていないアカウントに関しては、サーバーで発行したセッションIDをCookieに持っていない。
これで困るのがロギングのシーンである。未ログイン状態でアクセスしてくるユーザーが入り混じるため、とあるユーザーの行動をログから追跡することができない。
このようなシチュエーションに有用なのがCallIdである。
まずはbuild.gradle.kts
にインストール。
dependencies {
// 略
// for call id
implementation("io.ktor:ktor-server-call-id:$ktor_version")
//略
}
次にApplication.kt
からKtorにプラグインをインストールする。install
の中のverify
などについては後ほど詳しく説明する。
package example.koin
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.plugins.callid.*
import io.ktor.server.plugins.callloging.*
fun main(args: ArrayString>) {
io.ktor.server.tomcat.EngineMain.main(args)
}
fun Application.module() {
settingKoin()
configureRouting()
install(CallId) {
header(HttpHeaders.XRequestId)
verify { callId: String ->
callId.isNotEmpty()
}
}
install(CallLogging) {
callIdMdc("call-id")
}
}
最後にlogback.xml
にX-Request-ID
として付与されるCallId
を出力するための設定をいれる。%X{call-id}
がそう。
name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %X{call-id} %-5level %logger{36} - %msg%n
level="debug">
ref="STDOUT"/>
まずはX-Request-ID
の有無によるログ出力やレスポンスをみてみる。今回はinorinrinrin
というCallId
をマニュアルで付与する。
するとレスポンスヘッダにも同じものが設定されているのがわかる。これはheader()
が取得→送信をひとまとめにしてくれているからである。
ログをみると、X-Request-ID
に紐づいたCallId
が出力されているのがわかる。
今度はX-Request-ID
を外してリクエストを送信する。
すると今度はログにCallIdが出力されていないことがわかる。
これはverify
がX-Request-ID
の妥当性を検証しているからである。それを確認するため、verify
の条件をino
から始まる文字列にした場合にどうなるかをみてみる。
install(CallId) {
header(HttpHeaders.XRequestId)
verify { callId: String ->
+ callId.startsWith("ino")
}
}
X-Request-ID
をayaneru
としてみた。このとき、レスポンスヘッダにX-Request-ID
が返ってこない。ログにもCallId
は出ていない。
以上から、X-Request-ID
が付与されていれば以降の通信でそれを使いまわせること。ログに出力できることを確認できた。
あとはX-Request-ID
を初回リクエスト時に発行してあげればよい。CallId
を生成しX-Request-ID
に設定するにはgenerateを使う。
生成方法にはドキュメントに記載があるとおり、文字の種類を渡して適当な長さのIDを生成させるか、自前で生成する方法がある。
今回は自前生成関数generateRandomString
を定義してみる。
fun generateRandomString(length: Int): String {
val charPool = ('a'..'z') + ('A'..'Z') + ('0'..'9') // 小文字、大文字、数字
return (1..length)
.map { Random.nextInt(charPool.size) }
.map(charPool::get)
.joinToString("")
}
これをgenerate
に渡す。
install(CallId) {
header(HttpHeaders.XRequestId)
+ generate { generateRandomString(10) }
verify { callId: String ->
callId.isNotEmpty()
}
}
ではX-Request-ID
を付与しない初回のリクエストを見てみる。すると10文字のCallId
が生成され、レスポンスヘッダに付与されたのがわかる。
Ktorがロギングまで気を配ってくれているので非常にありがたい。この手の仕組みを数行で実現できるのは利用者からするとかなり楽。
Views: 0