0
# Advanced Configuration Features
1
2
The Ktor Client Logging plugin provides advanced security and filtering capabilities for fine-tuned control over logging behavior.
3
4
## Required Imports
5
6
```kotlin
7
import io.ktor.client.*
8
import io.ktor.client.plugins.logging.*
9
import io.ktor.client.request.*
10
import io.ktor.http.*
11
```
12
13
## Request Filtering
14
15
Filter which HTTP requests get logged based on custom criteria.
16
17
```kotlin { .api }
18
fun LoggingConfig.filter(predicate: (HttpRequestBuilder) -> Boolean)
19
```
20
21
**Parameters:**
22
- `predicate`: Function that receives an `HttpRequestBuilder` and returns `true` if the request should be logged
23
24
Multiple filters can be added and they work with OR logic - if any filter returns `true`, the request will be logged.
25
26
### Common Filtering Patterns
27
28
#### Host-Based Filtering
29
```kotlin
30
Logging {
31
// Only log requests to specific hosts
32
filter { request ->
33
request.url.host in listOf("api.production.com", "auth.production.com")
34
}
35
36
// Exclude localhost requests
37
filter { request ->
38
!request.url.host.contains("localhost")
39
}
40
}
41
```
42
43
#### Method-Based Filtering
44
```kotlin
45
Logging {
46
// Only log non-GET requests
47
filter { request ->
48
request.method != HttpMethod.Get
49
}
50
51
// Only log specific methods
52
filter { request ->
53
request.method in listOf(HttpMethod.Post, HttpMethod.Put, HttpMethod.Delete)
54
}
55
}
56
```
57
58
#### Path-Based Filtering
59
```kotlin
60
Logging {
61
// Only log API endpoints
62
filter { request ->
63
request.url.pathSegments.any { it == "api" }
64
}
65
66
// Exclude health check endpoints
67
filter { request ->
68
!request.url.encodedPath.contains("/health")
69
}
70
71
// Log only specific resource types
72
filter { request ->
73
request.url.pathSegments.any { segment ->
74
segment in listOf("users", "orders", "products")
75
}
76
}
77
}
78
```
79
80
#### Header-Based Filtering
81
```kotlin
82
Logging {
83
// Only log requests with specific headers
84
filter { request ->
85
request.headers.contains("X-Debug-Mode")
86
}
87
88
// Only log authenticated requests
89
filter { request ->
90
request.headers.contains(HttpHeaders.Authorization)
91
}
92
}
93
```
94
95
#### Complex Filtering Logic
96
```kotlin
97
Logging {
98
// Multiple conditions
99
filter { request ->
100
request.url.host == "api.production.com" &&
101
request.method == HttpMethod.Post &&
102
request.url.pathSegments.contains("sensitive-operation")
103
}
104
105
// Environment-based filtering
106
filter { request ->
107
System.getProperty("logging.level") == "debug" ||
108
request.headers["X-Debug-Session"] != null
109
}
110
}
111
```
112
113
### Multiple Filters
114
```kotlin
115
Logging {
116
// All these filters work with OR logic
117
filter { it.url.host == "api.example.com" } // Log api.example.com
118
filter { it.method == HttpMethod.Post } // OR log all POST requests
119
filter { it.headers.contains("X-Debug") } // OR log requests with debug header
120
}
121
```
122
123
## Header Sanitization
124
125
Prevent sensitive header values from appearing in logs by replacing them with placeholder text.
126
127
```kotlin { .api }
128
fun LoggingConfig.sanitizeHeader(
129
placeholder: String = "***",
130
predicate: (String) -> Boolean
131
)
132
```
133
134
**Parameters:**
135
- `placeholder`: String to replace sensitive header values (default: "***")
136
- `predicate`: Function that receives a header name and returns `true` if it should be sanitized
137
138
Multiple sanitization rules can be added with different placeholders for different header types.
139
140
### Common Sanitization Patterns
141
142
#### Authentication Headers
143
```kotlin
144
Logging {
145
// Standard authentication headers
146
sanitizeHeader { headerName ->
147
headerName.equals(HttpHeaders.Authorization, ignoreCase = true)
148
}
149
150
// API key headers
151
sanitizeHeader("████") { headerName ->
152
headerName.lowercase().contains("api-key") ||
153
headerName.lowercase().contains("x-api")
154
}
155
}
156
```
157
158
#### Custom Security Headers
159
```kotlin
160
Logging {
161
// Custom security tokens
162
sanitizeHeader("[REDACTED]") { headerName ->
163
headerName.startsWith("X-Secret-") ||
164
headerName.endsWith("-Token") ||
165
headerName.contains("Password", ignoreCase = true)
166
}
167
168
// Session identifiers
169
sanitizeHeader("████████") { headerName ->
170
headerName.lowercase() in listOf("cookie", "set-cookie", "x-session-id")
171
}
172
}
173
```
174
175
#### Pattern-Based Sanitization
176
```kotlin
177
Logging {
178
// Headers starting with specific prefixes
179
sanitizeHeader { headerName ->
180
val sensitive = listOf("X-Private-", "X-Internal-", "X-Auth-")
181
sensitive.any { prefix -> headerName.startsWith(prefix, ignoreCase = true) }
182
}
183
184
// Headers containing sensitive keywords
185
sanitizeHeader("[HIDDEN]") { headerName ->
186
val keywords = listOf("secret", "private", "token", "key", "password", "credential")
187
keywords.any { keyword -> headerName.contains(keyword, ignoreCase = true) }
188
}
189
}
190
```
191
192
#### Different Placeholders for Different Types
193
```kotlin
194
Logging {
195
// Different visual indicators for different security levels
196
sanitizeHeader("🔐") { it.equals("Authorization", ignoreCase = true) }
197
sanitizeHeader("🗝️") { it.contains("api-key", ignoreCase = true) }
198
sanitizeHeader("🚫") { it.contains("private", ignoreCase = true) }
199
sanitizeHeader("[CLASSIFIED]") { it.startsWith("X-Secret-") }
200
}
201
```
202
203
### Sanitization Output Examples
204
205
**Before sanitization:**
206
```
207
-> Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
208
-> X-API-Key: sk_live_51HqJKaBC123...
209
-> X-Secret-Token: supersecretvalue123
210
```
211
212
**After sanitization:**
213
```
214
-> Authorization: ***
215
-> X-API-Key: ████
216
-> X-Secret-Token: [REDACTED]
217
```
218
219
## Combined Advanced Configuration
220
221
```kotlin
222
val client = HttpClient {
223
install(Logging) {
224
// Basic configuration
225
level = LogLevel.HEADERS
226
format = LoggingFormat.OkHttp
227
logger = Logger.DEFAULT
228
229
/* Request Filtering */
230
231
// Only log production API calls
232
filter { request ->
233
request.url.host == "api.production.com"
234
}
235
236
// Or log debug requests from any host
237
filter { request ->
238
request.headers.contains("X-Debug-Mode")
239
}
240
241
// Or log error-prone operations
242
filter { request ->
243
request.method in listOf(HttpMethod.Post, HttpMethod.Put, HttpMethod.Delete) &&
244
request.url.pathSegments.any { it in listOf("users", "payments", "orders") }
245
}
246
247
/* Header Sanitization */
248
249
// Standard auth headers
250
sanitizeHeader { it.equals("Authorization", ignoreCase = true) }
251
252
// API keys with different placeholder
253
sanitizeHeader("████") { headerName ->
254
listOf("x-api-key", "api-key", "x-auth-token").any {
255
headerName.equals(it, ignoreCase = true)
256
}
257
}
258
259
// Custom security headers
260
sanitizeHeader("[CLASSIFIED]") { headerName ->
261
headerName.startsWith("X-Secret-", ignoreCase = true) ||
262
headerName.startsWith("X-Private-", ignoreCase = true) ||
263
headerName.contains("password", ignoreCase = true)
264
}
265
266
// Session and cookie data
267
sanitizeHeader("🍪") { headerName ->
268
headerName.lowercase() in listOf("cookie", "set-cookie", "x-session-id")
269
}
270
}
271
}
272
```
273
274
## Security Best Practices
275
276
### Header Sanitization Guidelines
277
278
1. **Always sanitize authentication headers**: Authorization, API keys, tokens
279
2. **Use descriptive placeholders**: Different placeholders help identify header types
280
3. **Be comprehensive**: Consider all variations (X-API-Key, Api-Key, API_KEY, etc.)
281
4. **Review regularly**: Update sanitization rules as your API evolves
282
283
### Filtering Guidelines
284
285
1. **Filter in production**: Avoid logging all requests in production environments
286
2. **Use specific filters**: Target specific endpoints or operations rather than broad filtering
287
3. **Consider performance**: Complex filter predicates run for every request
288
4. **Test thoroughly**: Ensure important requests aren't accidentally filtered out
289
290
### Example Security-First Configuration
291
292
```kotlin
293
Logging {
294
// Conservative logging level for production
295
level = LogLevel.INFO
296
format = LoggingFormat.OkHttp
297
298
// Only log errors and important operations
299
filter { request ->
300
// Log authentication attempts
301
request.url.pathSegments.contains("auth") ||
302
// Log payment operations
303
request.url.pathSegments.contains("payments") ||
304
// Log admin operations
305
request.headers.contains("X-Admin-Request")
306
}
307
308
// Comprehensive header sanitization
309
sanitizeHeader { headerName ->
310
val sensitivePatterns = listOf(
311
"auth", "token", "key", "secret", "password",
312
"credential", "private", "session", "cookie"
313
)
314
sensitivePatterns.any { pattern ->
315
headerName.contains(pattern, ignoreCase = true)
316
}
317
}
318
}
319
```