CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-ktor--ktor-client-logging-jvm

HTTP client logging plugin for Ktor client framework with configurable logging formats, levels, and platform-specific logger integrations

Pending
Overview
Eval results
Files

advanced-config.mddocs/

Advanced Configuration Features

The Ktor Client Logging plugin provides advanced security and filtering capabilities for fine-tuned control over logging behavior.

Required Imports

import io.ktor.client.*
import io.ktor.client.plugins.logging.*
import io.ktor.client.request.*
import io.ktor.http.*

Request Filtering

Filter which HTTP requests get logged based on custom criteria.

fun LoggingConfig.filter(predicate: (HttpRequestBuilder) -> Boolean)

Parameters:

  • predicate: Function that receives an HttpRequestBuilder and returns true if the request should be logged

Multiple filters can be added and they work with OR logic - if any filter returns true, the request will be logged.

Common Filtering Patterns

Host-Based Filtering

Logging {
    // Only log requests to specific hosts
    filter { request -> 
        request.url.host in listOf("api.production.com", "auth.production.com")
    }
    
    // Exclude localhost requests
    filter { request -> 
        !request.url.host.contains("localhost")
    }
}

Method-Based Filtering

Logging {
    // Only log non-GET requests
    filter { request -> 
        request.method != HttpMethod.Get
    }
    
    // Only log specific methods
    filter { request ->
        request.method in listOf(HttpMethod.Post, HttpMethod.Put, HttpMethod.Delete)
    }
}

Path-Based Filtering

Logging {
    // Only log API endpoints
    filter { request -> 
        request.url.pathSegments.any { it == "api" }
    }
    
    // Exclude health check endpoints
    filter { request ->
        !request.url.encodedPath.contains("/health")
    }
    
    // Log only specific resource types
    filter { request ->
        request.url.pathSegments.any { segment ->
            segment in listOf("users", "orders", "products")
        }
    }
}

Header-Based Filtering

Logging {
    // Only log requests with specific headers
    filter { request ->
        request.headers.contains("X-Debug-Mode")
    }
    
    // Only log authenticated requests
    filter { request ->
        request.headers.contains(HttpHeaders.Authorization)
    }
}

Complex Filtering Logic

Logging {
    // Multiple conditions
    filter { request ->
        request.url.host == "api.production.com" && 
        request.method == HttpMethod.Post &&
        request.url.pathSegments.contains("sensitive-operation")
    }
    
    // Environment-based filtering
    filter { request ->
        System.getProperty("logging.level") == "debug" ||
        request.headers["X-Debug-Session"] != null
    }
}

Multiple Filters

Logging {
    // All these filters work with OR logic
    filter { it.url.host == "api.example.com" }  // Log api.example.com
    filter { it.method == HttpMethod.Post }       // OR log all POST requests
    filter { it.headers.contains("X-Debug") }     // OR log requests with debug header
}

Header Sanitization

Prevent sensitive header values from appearing in logs by replacing them with placeholder text.

fun LoggingConfig.sanitizeHeader(
    placeholder: String = "***", 
    predicate: (String) -> Boolean
)

Parameters:

  • placeholder: String to replace sensitive header values (default: "***")
  • predicate: Function that receives a header name and returns true if it should be sanitized

Multiple sanitization rules can be added with different placeholders for different header types.

Common Sanitization Patterns

Authentication Headers

Logging {
    // Standard authentication headers
    sanitizeHeader { headerName ->
        headerName.equals(HttpHeaders.Authorization, ignoreCase = true)
    }
    
    // API key headers
    sanitizeHeader("████") { headerName ->
        headerName.lowercase().contains("api-key") ||
        headerName.lowercase().contains("x-api")
    }
}

Custom Security Headers

Logging {
    // Custom security tokens
    sanitizeHeader("[REDACTED]") { headerName ->
        headerName.startsWith("X-Secret-") ||
        headerName.endsWith("-Token") ||
        headerName.contains("Password", ignoreCase = true)
    }
    
    // Session identifiers
    sanitizeHeader("████████") { headerName ->
        headerName.lowercase() in listOf("cookie", "set-cookie", "x-session-id")
    }
}

Pattern-Based Sanitization

Logging {
    // Headers starting with specific prefixes
    sanitizeHeader { headerName ->
        val sensitive = listOf("X-Private-", "X-Internal-", "X-Auth-")
        sensitive.any { prefix -> headerName.startsWith(prefix, ignoreCase = true) }
    }
    
    // Headers containing sensitive keywords
    sanitizeHeader("[HIDDEN]") { headerName ->
        val keywords = listOf("secret", "private", "token", "key", "password", "credential")
        keywords.any { keyword -> headerName.contains(keyword, ignoreCase = true) }
    }
}

Different Placeholders for Different Types

Logging {
    // Different visual indicators for different security levels
    sanitizeHeader("🔐") { it.equals("Authorization", ignoreCase = true) }
    sanitizeHeader("🗝️") { it.contains("api-key", ignoreCase = true) }
    sanitizeHeader("🚫") { it.contains("private", ignoreCase = true) }
    sanitizeHeader("[CLASSIFIED]") { it.startsWith("X-Secret-") }
}

Sanitization Output Examples

Before sanitization:

-> Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
-> X-API-Key: sk_live_51HqJKaBC123...
-> X-Secret-Token: supersecretvalue123

After sanitization:

-> Authorization: ***
-> X-API-Key: ████
-> X-Secret-Token: [REDACTED]

Combined Advanced Configuration

val client = HttpClient {
    install(Logging) {
        // Basic configuration
        level = LogLevel.HEADERS
        format = LoggingFormat.OkHttp
        logger = Logger.DEFAULT
        
        /* Request Filtering */
        
        // Only log production API calls
        filter { request ->
            request.url.host == "api.production.com"
        }
        
        // Or log debug requests from any host
        filter { request ->
            request.headers.contains("X-Debug-Mode")
        }
        
        // Or log error-prone operations
        filter { request ->
            request.method in listOf(HttpMethod.Post, HttpMethod.Put, HttpMethod.Delete) &&
            request.url.pathSegments.any { it in listOf("users", "payments", "orders") }
        }
        
        /* Header Sanitization */
        
        // Standard auth headers
        sanitizeHeader { it.equals("Authorization", ignoreCase = true) }
        
        // API keys with different placeholder
        sanitizeHeader("████") { headerName ->
            listOf("x-api-key", "api-key", "x-auth-token").any { 
                headerName.equals(it, ignoreCase = true) 
            }
        }
        
        // Custom security headers
        sanitizeHeader("[CLASSIFIED]") { headerName ->
            headerName.startsWith("X-Secret-", ignoreCase = true) ||
            headerName.startsWith("X-Private-", ignoreCase = true) ||
            headerName.contains("password", ignoreCase = true)
        }
        
        // Session and cookie data
        sanitizeHeader("🍪") { headerName ->
            headerName.lowercase() in listOf("cookie", "set-cookie", "x-session-id")
        }
    }
}

Security Best Practices

Header Sanitization Guidelines

  1. Always sanitize authentication headers: Authorization, API keys, tokens
  2. Use descriptive placeholders: Different placeholders help identify header types
  3. Be comprehensive: Consider all variations (X-API-Key, Api-Key, API_KEY, etc.)
  4. Review regularly: Update sanitization rules as your API evolves

Filtering Guidelines

  1. Filter in production: Avoid logging all requests in production environments
  2. Use specific filters: Target specific endpoints or operations rather than broad filtering
  3. Consider performance: Complex filter predicates run for every request
  4. Test thoroughly: Ensure important requests aren't accidentally filtered out

Example Security-First Configuration

Logging {
    // Conservative logging level for production
    level = LogLevel.INFO
    format = LoggingFormat.OkHttp
    
    // Only log errors and important operations
    filter { request ->
        // Log authentication attempts
        request.url.pathSegments.contains("auth") ||
        // Log payment operations
        request.url.pathSegments.contains("payments") ||
        // Log admin operations
        request.headers.contains("X-Admin-Request")
    }
    
    // Comprehensive header sanitization
    sanitizeHeader { headerName ->
        val sensitivePatterns = listOf(
            "auth", "token", "key", "secret", "password", 
            "credential", "private", "session", "cookie"
        )
        sensitivePatterns.any { pattern ->
            headerName.contains(pattern, ignoreCase = true)
        }
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-io-ktor--ktor-client-logging-jvm

docs

advanced-config.md

configuration.md

index.md

levels-formats.md

loggers.md

platform-features.md

tile.json