Ktor HTTP client logging plugin for JavaScript targets providing comprehensive request/response logging capabilities with configurable levels, formats, and header sanitization
npx @tessl/cli install tessl/maven-io-ktor--ktor-client-logging-js@3.2.0Ktor Client Logging Plugin provides comprehensive HTTP request and response logging capabilities for Ktor HTTP client applications targeting JavaScript environments. It offers configurable logging levels, multiple output formats, header sanitization, and platform-specific logger implementations optimized for browser and Node.js environments.
implementation("io.ktor:ktor-client-logging-js:3.2.0")import io.ktor.client.plugins.logging.*For HttpClient configuration:
import io.ktor.client.*
import io.ktor.client.plugins.logging.*import io.ktor.client.*
import io.ktor.client.plugins.logging.*
// Basic setup with default configuration
val client = HttpClient {
install(Logging)
}
// Configured setup
val client = HttpClient {
install(Logging) {
level = LogLevel.ALL
logger = Logger.SIMPLE
}
}
// Advanced configuration
val client = HttpClient {
install(Logging) {
level = LogLevel.HEADERS
format = LoggingFormat.OkHttp
logger = Logger.DEFAULT
// Filter requests
filter { request ->
request.url.host == "api.example.com"
}
// Sanitize sensitive headers
sanitizeHeader { header ->
header == "Authorization"
}
}
}Install and configure the logging plugin for HTTP clients.
/**
* Main logging plugin that provides HTTP call logging capabilities
*/
val Logging: ClientPlugin<LoggingConfig>
/**
* Convenience function to configure and install the Logging plugin
*/
fun HttpClientConfig<*>.Logging(block: LoggingConfig.() -> Unit = {})
/**
* Configuration for the Logging plugin
*/
@KtorDsl
class LoggingConfig {
/** General format for logging requests and responses */
var format: LoggingFormat
/** Logger instance for output */
var logger: Logger
/** Logging level controlling what gets logged */
var level: LogLevel
/** Add a filter predicate for conditional logging */
fun filter(predicate: (HttpRequestBuilder) -> Boolean)
/** Sanitize sensitive headers to avoid values appearing in logs */
fun sanitizeHeader(placeholder: String = "***", predicate: (String) -> Boolean)
}Control the amount of information logged for HTTP requests and responses.
/**
* Logging level enumeration with boolean properties
*/
enum class LogLevel(
val info: Boolean,
val headers: Boolean,
val body: Boolean
) {
/** Log everything: info, headers, and body */
ALL(true, true, true),
/** Log info and headers, but not body */
HEADERS(true, true, false),
/** Log info and body, but not headers */
BODY(true, false, true),
/** Log only basic request/response info */
INFO(true, false, false),
/** No logging */
NONE(false, false, false)
}Choose between different output formats for logged messages.
/**
* Output format for logged messages
*/
enum class LoggingFormat {
/** Standard Ktor logging format */
Default,
/**
* OkHttp-compatible logging format for application-level logs
* Writes only application-level logs because low-level HTTP communication
* is hidden within engine implementations
*/
OkHttp
}Core logging interface and built-in implementations for different environments.
/**
* Core logging interface for HTTP client
*/
interface Logger {
/** Add message to log */
fun log(message: String)
companion object
}
/** Default logger for JS/WASM platforms (delegates to SIMPLE) */
val Logger.Companion.DEFAULT: Logger
/** Simple logger using println with "HttpClient:" prefix */
val Logger.Companion.SIMPLE: Logger
/** Empty logger for testing (no-op implementation) */
val Logger.Companion.EMPTY: LoggerUsage Examples:
// Using default logger
val client = HttpClient {
install(Logging) {
logger = Logger.DEFAULT
}
}
// Using simple console logger
val client = HttpClient {
install(Logging) {
logger = Logger.SIMPLE
}
}
// Using empty logger for tests
val client = HttpClient {
install(Logging) {
logger = Logger.EMPTY
}
}
// Custom logger implementation
val customLogger = object : Logger {
override fun log(message: String) {
console.log("MyApp HTTP: $message")
}
}
val client = HttpClient {
install(Logging) {
logger = customLogger
}
}Control which HTTP calls get logged using predicate functions.
/**
* Add a filter predicate for conditional logging
* @param predicate Function that returns true if the request should be logged
*/
fun LoggingConfig.filter(predicate: (HttpRequestBuilder) -> Boolean)Usage Examples:
val client = HttpClient {
install(Logging) {
// Only log API calls
filter { request ->
request.url.host.contains("api")
}
// Only log POST requests
filter { request ->
request.method == HttpMethod.Post
}
// Multiple filters (all must pass)
filter { request -> request.url.protocol.isSecure() }
filter { request -> !request.url.pathSegments.contains("health") }
}
}Sanitize sensitive headers to prevent their values from appearing in logs.
/**
* Sanitize sensitive headers to avoid their values appearing in the logs
* @param placeholder Replacement text for sanitized values (default: "***")
* @param predicate Function that returns true if the header should be sanitized
*/
fun LoggingConfig.sanitizeHeader(placeholder: String = "***", predicate: (String) -> Boolean)Usage Examples:
val client = HttpClient {
install(Logging) {
level = LogLevel.HEADERS
// Sanitize Authorization header with default placeholder
sanitizeHeader { header ->
header == "Authorization"
}
// Sanitize multiple headers with custom placeholder
sanitizeHeader("█████") { header ->
header in listOf("Authorization", "X-API-Key", "Cookie")
}
// Case-insensitive sanitization
sanitizeHeader { header ->
header.lowercase() == "authorization"
}
}
}/**
* HTTP request builder used in filter predicates
*/
class HttpRequestBuilder {
val url: URLBuilder
val method: HttpMethod
val headers: HeadersBuilder
val body: Any
val attributes: Attributes
}
/**
* HTTP method enumeration
*/
class HttpMethod {
companion object {
val Get: HttpMethod
val Post: HttpMethod
val Put: HttpMethod
val Delete: HttpMethod
val Head: HttpMethod
val Options: HttpMethod
val Patch: HttpMethod
}
}
/**
* URL builder for constructing and examining URLs
*/
class URLBuilder {
val protocol: URLProtocol
var host: String
var port: Int
val pathSegments: List<String>
val parameters: ParametersBuilder
}
/**
* Headers builder for HTTP headers
*/
class HeadersBuilder {
fun append(name: String, value: String)
fun contains(name: String): Boolean
operator fun get(name: String): String?
}
/**
* URL protocol with name and default port
*/
data class URLProtocol(val name: String, val defaultPort: Int) {
companion object {
val HTTP: URLProtocol
val HTTPS: URLProtocol
val WS: URLProtocol
val WSS: URLProtocol
}
}
/**
* Check if the protocol is secure (HTTPS or WSS)
*/
fun URLProtocol.isSecure(): Boolean
/**
* Parameters builder for URL parameters
*/
class ParametersBuilder {
fun append(name: String, value: String)
fun contains(name: String): Boolean
operator fun get(name: String): String?
}
/**
* Attributes container for request metadata
*/
class Attributes {
fun <T : Any> put(key: AttributeKey<T>, value: T)
operator fun <T : Any> get(key: AttributeKey<T>): T
fun <T : Any> contains(key: AttributeKey<T>): Boolean
}
/**
* Attribute key for type-safe attribute access
*/
class AttributeKey<T : Any>(val name: String)The JavaScript version of the logging plugin provides optimized integration with browser and Node.js environments:
The plugin gracefully handles various error conditions:
Advanced content handling capabilities:
val client = HttpClient {
install(Logging) {
level = LogLevel.ALL
logger = Logger.SIMPLE
}
}val client = HttpClient {
install(Logging) {
level = LogLevel.INFO
logger = Logger.DEFAULT
// Only log errors and important requests
filter { request ->
request.url.pathSegments.none { it == "health" }
}
// Sanitize all sensitive headers
sanitizeHeader { header ->
header.lowercase() in listOf("authorization", "x-api-key", "cookie")
}
}
}val client = HttpClient {
install(Logging) {
level = LogLevel.BODY
format = LoggingFormat.OkHttp
logger = Logger.DEFAULT
}
}val client = HttpClient {
install(Logging) {
logger = Logger.EMPTY // No output during tests
}
}