HTTP client logging plugin for Ktor framework with configurable log levels and header sanitization support
pkg:kotlin/io.ktor/ktor-client-logging-macosx64@2.3.x
npx @tessl/cli install tessl/kotlin-io-ktor--ktor-client-logging-macosx64@2.3.0Ktor Client Logging provides comprehensive HTTP client logging capabilities for the Ktor framework. It offers configurable logging levels, request/response filtering, header sanitization, and platform-specific logger implementations with full coroutine support.
build.gradle.kts dependenciesimport io.ktor.client.plugins.logging.*
import io.ktor.client.*import io.ktor.client.*
import io.ktor.client.plugins.logging.*
// Basic logging configuration
val client = HttpClient {
install(Logging) {
level = LogLevel.HEADERS
logger = Logger.DEFAULT
}
}
// Advanced configuration with filtering and sanitization
val client = HttpClient {
install(Logging) {
level = LogLevel.ALL
logger = Logger.SIMPLE
// Filter requests to only log specific URLs
filter { request ->
request.url.host.contains("api.example.com")
}
// Sanitize sensitive headers
sanitizeHeader("***") { header ->
header == "Authorization" || header == "API-Key"
}
}
}
// Make logged HTTP requests
client.get("https://api.example.com/users")Ktor Client Logging integrates with the Ktor HTTP client pipeline through several key components:
HttpClientPlugin for seamless integration with Ktor clientsMain plugin class providing HTTP client logging capabilities with extensive configuration options.
/**
* A client's plugin that provides the capability to log HTTP calls.
*/
class Logging private constructor(
val logger: Logger,
var level: LogLevel,
var filters: List<(HttpRequestBuilder) -> Boolean> = emptyList()
) {
companion object : HttpClientPlugin<Config, Logging> {
override val key: AttributeKey<Logging>
override fun prepare(block: Config.() -> Unit): Logging
override fun install(plugin: Logging, scope: HttpClient)
}
}
/**
* A configuration for the Logging plugin.
*/
class Logging.Config {
/** 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 */
fun filter(predicate: (HttpRequestBuilder) -> Boolean)
/** Allows you to sanitize sensitive headers to avoid their values appearing in the logs */
fun sanitizeHeader(placeholder: String = "***", predicate: (String) -> Boolean)
}
/**
* Configures and installs Logging in HttpClient.
*/
fun HttpClientConfig<*>.Logging(block: Logging.Config.() -> Unit = {})Defines the verbosity and scope of HTTP logging operations.
/**
* Logging log level.
*/
enum class LogLevel(
val info: Boolean,
val headers: Boolean,
val body: Boolean
) {
/** Log everything: request/response info, headers, and body content */
ALL(true, true, true),
/** Log request/response info and headers, but not body content */
HEADERS(true, true, false),
/** Log request/response info and body content, but not headers */
BODY(true, false, true),
/** Log only basic request/response information */
INFO(true, false, false),
/** Disable all logging */
NONE(false, false, false)
}Core logging abstraction with platform-specific implementations.
/**
* HttpClient Logger interface.
*/
interface Logger {
/** Add message to log */
fun log(message: String)
companion object
}/**
* Default logger to use (platform-specific implementation).
*/
val Logger.Companion.DEFAULT: Logger
/**
* Logger using println for simple console output.
*/
val Logger.Companion.SIMPLE: Logger
/**
* Empty Logger for test purposes - logs nothing.
*/
val Logger.Companion.EMPTY: Logger/**
* Message Length Limiting Logger: Breaks up log messages into multiple logs no longer than maxLength.
* Useful for platforms with log message length limitations.
*/
class MessageLengthLimitingLogger(
private val maxLength: Int = 4000,
private val minLength: Int = 3000,
private val delegate: Logger = Logger.DEFAULT
) : Logger {
override fun log(message: String)
}/**
* HTTP request builder type for filtering predicates.
*/
typealias HttpRequestBuilder = io.ktor.client.request.HttpRequestBuilderimport io.ktor.client.*
import io.ktor.client.plugins.logging.*
import io.ktor.client.request.*
val client = HttpClient {
install(Logging) {
level = LogLevel.INFO
}
}
// This will log basic request/response information
val response = client.get("https://httpbin.org/get")val client = HttpClient {
install(Logging) {
level = LogLevel.ALL
logger = Logger.SIMPLE
}
}
// This will log complete request/response including headers and body
val response = client.post("https://httpbin.org/post") {
setBody("Request body content")
}val client = HttpClient {
install(Logging) {
level = LogLevel.HEADERS
logger = Logger.DEFAULT
// Only log requests to specific domains
filter { request ->
request.url.host.endsWith("example.com")
}
// Sanitize authorization headers
sanitizeHeader("***") { headerName ->
headerName.equals("Authorization", ignoreCase = true)
}
// Sanitize multiple header types
sanitizeHeader("[REDACTED]") { headerName ->
headerName in listOf("API-Key", "X-Auth-Token", "Cookie")
}
}
}// On Native platforms, use simple console logging
val client = HttpClient {
install(Logging) {
level = LogLevel.HEADERS
logger = Logger.SIMPLE // Console logging for Native platforms
}
}class CustomLogger : Logger {
override fun log(message: String) {
// Custom logging logic - could write to file, send to analytics, etc.
println("[CUSTOM] $message")
}
}
val client = HttpClient {
install(Logging) {
level = LogLevel.ALL
logger = CustomLogger()
}
}val client = HttpClient {
install(Logging) {
level = LogLevel.HEADERS
// Log only successful responses
filter { request ->
// This will be evaluated for each request
request.url.host.contains("api")
}
// Add multiple filters
filter { request ->
request.method.value == "POST"
}
}
}The Logging plugin handles errors gracefully: