Tracing requests in Ktor Server
The CallId plugin allows you to trace client requests end-to-end by using unique request IDs or call IDs. Typically, working with a call ID in Ktor might look as follows:
First, you need to obtain a call ID for a specific request in one of the following ways:
Next, Ktor verifies a retrieved/generated call ID using a predefined dictionary. You can also provide your own condition to verify a call ID.
Finally, you can send a call ID to the client in a specific header, for example,
X-Request-Id.
Using CallId along with CallLogging helps you troubleshoot calls by putting a call ID in the MDC context and configuring a logger to show a call ID for each request.
Add dependencies
To use CallId, add the ktor-server-call-id artifact to your build script:
Install CallId
To install the CallId plugin to your application, pass it to the install function in the specified module. The following examples show how to install CallId:
In an
embeddedServer()function call.In an explicitly defined
module()extension function on theApplicationclass.
Configure CallId
Retrieve a call ID
CallId provides several ways to retrieve a call ID:
To retrieve a call ID from the specified header, use the
retrieveFromHeaderfunction, for example:install(CallId) { retrieveFromHeader(HttpHeaders.XRequestId) }You can also use the
headerfunction to retrieve and send a call ID in the same header.If required, you can retrieve a call ID from the
ApplicationCall:install(CallId) { retrieve { call -> call.request.header(HttpHeaders.XRequestId) } }
Note that all retrieved call IDs are verified using a default dictionary.
Generate a call ID
If an incoming request doesn't include a call ID, you can generate it using the generate function:
The example below shows how to generate a call ID with a specific length from the predefined dictionary:
install(CallId) { generate(10, "abcde12345") }In the example below, the
generatefunction accepts a block for generating a call ID:install(CallId) { val counter = atomic(0) generate { "generated-call-id-${counter.getAndIncrement()}" } }
Verify a call ID
All retrieved/generated call IDs are verified using a default dictionary, which looks as follows:
This means that call IDs containing capital letters won't pass verification. If required, you can apply less strict rules by using the verify function:
You can find the full example here: call-id.
Send a call ID to the client
After retrieving/generating a call ID, you can send it to the client:
The
headerfunction can be used to retrieve a call ID and send it in the same header:install(CallId) { header(HttpHeaders.XRequestId) }You can find the full example here: call-id.
The
replyToHeaderfunction sends a call ID in the specified header:install(CallId) { replyToHeader(HttpHeaders.XRequestId) }If required, you can use
ApplicationCallto send a call ID in a response:reply { call, callId -> call.response.header(HttpHeaders.XRequestId, callId) }
Put a call ID into MDC
Using CallId along with CallLogging helps you troubleshoot calls by putting a call ID in the MDC context and configuring a logger to show a call ID for each request. To do this, call the callIdMdc function inside the CallLogging configuration block and specify the desired key to be put in the MDC context:
This key can be passed to a logger configuration to show call IDs in the log. For instance, the logback.xml file might look as follows:
You can find the full example here: call-id.