Logging plugin for Ktor HTTP client that provides comprehensive request and response logging capabilities with configurable loggers, levels, and sanitization for sensitive data
—
Comprehensive configuration options for the Ktor Client Logging plugin, including logging levels, output formats, filtering, and header sanitization.
Install and configure the logging plugin in your HttpClient.
/**
* A client's plugin that provides the capability to log HTTP calls
*/
val Logging: ClientPlugin<LoggingConfig>
/**
* Configures and installs Logging in HttpClient
* @param block Configuration lambda for LoggingConfig
*/
fun HttpClientConfig<*>.Logging(block: LoggingConfig.() -> Unit = {})Usage Examples:
import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.logging.*
// Basic installation
val client = HttpClient(CIO) {
install(Logging)
}
// With configuration
val client = HttpClient(CIO) {
install(Logging) {
level = LogLevel.ALL
logger = Logger.SIMPLE
format = LoggingFormat.OkHttp
}
}
// Alternative syntax
val client = HttpClient(CIO) {
Logging {
level = LogLevel.HEADERS
}
}The main configuration class providing DSL-style configuration options.
/**
* A configuration for the Logging plugin
*/
@KtorDsl
class LoggingConfig {
/**
* A general format for logging requests and responses
*/
var format: LoggingFormat
/**
* Specifies a Logger instance
*/
var logger: Logger
/**
* Specifies the logging level
*/
var level: LogLevel
/**
* Allows you to filter log messages for calls matching a predicate
* @param predicate Function that receives HttpRequestBuilder and returns Boolean
*/
fun filter(predicate: (HttpRequestBuilder) -> Boolean)
/**
* Allows you to sanitize sensitive headers to avoid their values appearing in the logs
* @param placeholder String to replace sensitive header values (default: "***")
* @param predicate Function that receives header name and returns Boolean
*/
fun sanitizeHeader(placeholder: String = "***", predicate: (String) -> Boolean)
}
/**
* Internal data class for header sanitization configuration
*/
internal class SanitizedHeader(
val placeholder: String,
val predicate: (String) -> Boolean
)Control the amount of information logged for each request/response.
/**
* Logging log level
* @param info Whether to log basic request/response info
* @param headers Whether to log headers
* @param body Whether to log request/response body
*/
enum class LogLevel(
val info: Boolean,
val headers: Boolean,
val body: Boolean
) {
/** Log everything: request info, headers, and body */
ALL(true, true, true),
/** Log request info and headers, but not body */
HEADERS(true, true, false),
/** Log request info and body, but not headers */
BODY(true, false, true),
/** Log only basic request info */
INFO(true, false, false),
/** Disable logging */
NONE(false, false, false)
}Usage Examples:
install(Logging) {
level = LogLevel.ALL // Log everything
level = LogLevel.HEADERS // Log info + headers (default)
level = LogLevel.BODY // Log info + body
level = LogLevel.INFO // Log basic info only
level = LogLevel.NONE // No logging
}Choose between different output formats for logged information.
/**
* General format for logging requests and responses
*/
enum class LoggingFormat {
/** Standard Ktor logging format */
Default,
/**
* OkHttp logging format
* Writes only application-level logs because the low-level HTTP communication
* is hidden within the engine implementations
*/
OkHttp
}Usage Examples:
install(Logging) {
format = LoggingFormat.Default // Standard Ktor format
format = LoggingFormat.OkHttp // OkHttp-compatible format
}Filter which requests should be logged based on custom criteria.
/**
* Add a filter predicate to control which requests are logged
* @param predicate Function receiving HttpRequestBuilder, returns true to log
*/
fun LoggingConfig.filter(predicate: (HttpRequestBuilder) -> Boolean)Usage Examples:
import io.ktor.client.request.*
import io.ktor.http.*
install(Logging) {
// Only log requests to specific host
filter { request ->
request.url.host == "api.example.com"
}
// Only log POST requests
filter { request ->
request.method == HttpMethod.Post
}
// Only log requests with specific header
filter { request ->
request.headers.contains("X-Debug")
}
// Combine multiple filters (all must return true)
filter { request -> request.url.host == "api.example.com" }
filter { request -> request.method == HttpMethod.Post }
}Protect sensitive header values from appearing in logs.
/**
* Sanitize sensitive headers to avoid their values appearing in the logs
* @param placeholder String to replace sensitive values with (default: "***")
* @param predicate Function receiving header name, returns true to sanitize
*/
fun LoggingConfig.sanitizeHeader(placeholder: String = "***", predicate: (String) -> Boolean)Usage Examples:
import io.ktor.http.*
install(Logging) {
// Sanitize Authorization header with default placeholder
sanitizeHeader { header ->
header == HttpHeaders.Authorization
}
// Sanitize multiple headers with custom placeholder
sanitizeHeader("██") { header ->
header == "X-API-Key" || header == "X-Secret-Token"
}
// Sanitize headers by pattern
sanitizeHeader("[REDACTED]") { header ->
header.lowercase().contains("auth") ||
header.lowercase().contains("key") ||
header.lowercase().contains("token")
}
// Multiple sanitization rules
sanitizeHeader("***") { it == HttpHeaders.Authorization }
sanitizeHeader("██") { it.startsWith("X-Secret-") }
}val client = HttpClient(CIO) {
install(Logging) {
level = LogLevel.INFO // Basic info only in production
logger = Logger.DEFAULT // Use SLF4J/platform logger
// Only log failed requests
filter { request ->
// This would require additional logic to detect failures
true
}
// Sanitize all sensitive headers
sanitizeHeader { header ->
val sensitiveHeaders = setOf(
"Authorization", "X-API-Key", "X-Auth-Token",
"Cookie", "Set-Cookie", "X-Secret"
)
header in sensitiveHeaders
}
}
}val client = HttpClient(CIO) {
install(Logging) {
level = LogLevel.ALL // Log everything for debugging
logger = Logger.SIMPLE // Console output
format = LoggingFormat.OkHttp // Readable format
// Log only API calls (skip assets)
filter { request ->
!request.url.pathSegments.any { it.contains('.') }
}
}
}val client = HttpClient(CIO) {
install(Logging) {
level = LogLevel.HEADERS // Good balance for test visibility
logger = Logger.EMPTY // No output during tests
// Only log specific test scenarios
filter { request ->
request.headers.contains("X-Test-Scenario")
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-io-ktor--ktor-client-logging