0
# Platform-Specific Features
1
2
The Ktor Client Logging plugin provides platform-optimized implementations and features tailored to different runtime environments.
3
4
## Required Imports
5
6
```kotlin
7
import io.ktor.client.*
8
import io.ktor.client.plugins.logging.*
9
import kotlinx.coroutines.*
10
import org.slf4j.MDC // JVM only
11
import kotlin.coroutines.CoroutineContext
12
```
13
14
## JVM Platform Features
15
16
### SLF4J Integration
17
18
The JVM implementation seamlessly integrates with SLF4J, the standard logging facade for Java applications.
19
20
```kotlin { .api }
21
val Logger.Companion.DEFAULT: Logger
22
```
23
24
**JVM Implementation Details:**
25
- Uses `LoggerFactory.getLogger(HttpClient::class.java)`
26
- Logs at INFO level through SLF4J
27
- Respects your SLF4J configurations (logback.xml, log4j2.xml, etc.)
28
- Thread-safe for concurrent HTTP clients
29
30
**Configuration Example:**
31
```kotlin
32
// Inherits your SLF4J configuration
33
Logging {
34
logger = Logger.DEFAULT // Uses SLF4J
35
level = LogLevel.ALL
36
}
37
```
38
39
### Android Logcat Support
40
41
Special Android-optimized logger with Logcat integration and automatic message chunking.
42
43
```kotlin { .api }
44
val Logger.Companion.ANDROID: Logger
45
```
46
47
**Features:**
48
- **Automatic Logcat Detection**: Uses `android.util.Log` when available
49
- **SLF4J Fallback**: Falls back to SLF4J if Logcat is unavailable
50
- **Message Length Limiting**: Breaks long messages to fit Android's log constraints
51
- **Tag Management**: Uses "Ktor Client" as the log tag
52
- **Lazy Initialization**: Created on first access for optimal performance
53
54
**Android-Specific Behavior:**
55
- Maximum message length: 4000 characters
56
- Prefers newline breaks between 3000-4000 characters
57
- Graceful fallback if `android.util.Log` class not found
58
- Thread-safe for Android's multi-threaded environment
59
60
**Usage in Android Projects:**
61
```kotlin
62
val client = HttpClient {
63
install(Logging) {
64
logger = Logger.ANDROID
65
level = LogLevel.HEADERS
66
}
67
}
68
```
69
70
### MDC Context Propagation
71
72
Maintain Mapped Diagnostic Context (MDC) across coroutine boundaries for enhanced logging correlation.
73
74
```kotlin { .api }
75
// JVM Platform
76
actual fun MDCContext(): CoroutineContext.Element
77
78
// JavaScript/WASM Platform
79
actual fun MDCContext(): CoroutineContext.Element
80
81
// Native/Posix Platform
82
actual fun MDCContext(): CoroutineContext.Element
83
```
84
85
**Purpose:**
86
- Preserves SLF4J MDC context in coroutine-based HTTP operations
87
- Enables request correlation across async operations
88
- Supports structured logging and distributed tracing
89
90
**Usage with Coroutines:**
91
```kotlin
92
// Set up MDC context
93
MDC.put("requestId", "req-123")
94
MDC.put("userId", "user-456")
95
96
// Create client with MDC context preservation
97
val client = HttpClient {
98
install(Logging) {
99
logger = Logger.DEFAULT // Will include MDC context
100
level = LogLevel.INFO
101
}
102
}
103
104
// MDC context is automatically propagated through coroutines
105
runBlocking(MDCContext()) {
106
val response = client.get("https://api.example.com/data")
107
// Logs will include requestId and userId from MDC
108
}
109
```
110
111
**Integration with Structured Logging:**
112
```kotlin
113
// Example with logback-structured-config
114
MDC.put("traceId", UUID.randomUUID().toString())
115
MDC.put("operation", "user-creation")
116
117
val client = HttpClient {
118
install(Logging) {
119
logger = Logger.DEFAULT
120
level = LogLevel.ALL
121
filter { request ->
122
request.url.pathSegments.contains("users")
123
}
124
}
125
}
126
127
withContext(MDCContext()) {
128
// All HTTP logs will include traceId and operation
129
client.post("https://api.example.com/users") {
130
contentType(ContentType.Application.Json)
131
setBody(userCreateRequest)
132
}
133
}
134
```
135
136
## JavaScript/WASM Platform Features
137
138
### Console Integration
139
140
```kotlin { .api }
141
val Logger.Companion.DEFAULT: Logger // Points to Logger.SIMPLE
142
```
143
144
**Features:**
145
- Uses browser console or Node.js console
146
- Simple console.log implementation
147
- No additional dependencies
148
- Works in both browser and Node.js environments
149
150
**Browser Example:**
151
```kotlin
152
val client = HttpClient {
153
install(Logging) {
154
logger = Logger.DEFAULT // Uses console
155
level = LogLevel.INFO
156
}
157
}
158
```
159
160
## Native/Posix Platform Features
161
162
### Standard Output Integration
163
164
```kotlin { .api }
165
val Logger.Companion.DEFAULT: Logger // Points to Logger.SIMPLE
166
```
167
168
**Features:**
169
- Uses platform's standard output
170
- Minimal overhead implementation
171
- Compatible with native compilation
172
- Works across all supported native targets
173
174
## Platform-Specific Logger Selection
175
176
### Automatic Platform Detection
177
178
The `Logger.DEFAULT` implementation automatically selects the most appropriate logging mechanism for each platform:
179
180
```kotlin
181
// Same code works across all platforms
182
val client = HttpClient {
183
install(Logging) {
184
logger = Logger.DEFAULT
185
level = LogLevel.HEADERS
186
}
187
}
188
```
189
190
**Platform Mappings:**
191
- **JVM**: SLF4J-based logger with HttpClient class logger
192
- **Android**: Same as JVM (use `Logger.ANDROID` for Logcat)
193
- **JavaScript**: Browser console or Node.js console
194
- **WASM**: Browser console
195
- **Native**: Platform standard output
196
197
### Platform-Specific Optimizations
198
199
#### JVM Optimizations
200
```kotlin
201
val client = HttpClient {
202
install(Logging) {
203
// Leverage SLF4J configuration
204
logger = Logger.DEFAULT
205
206
// Use Android-specific features if needed
207
logger = Logger.ANDROID
208
209
// Or customize with message limiting
210
logger = MessageLengthLimitingLogger(
211
maxLength = 8000, // Higher limit for JVM
212
delegate = Logger.DEFAULT
213
)
214
215
level = LogLevel.ALL
216
}
217
}
218
```
219
220
#### Mobile/Android Optimizations
221
```kotlin
222
val client = HttpClient {
223
install(Logging) {
224
// Optimized for Android Logcat
225
logger = Logger.ANDROID
226
227
// Conservative logging to preserve performance/battery
228
level = LogLevel.INFO
229
format = LoggingFormat.OkHttp // More compact
230
231
// Filter to reduce log volume
232
filter { request ->
233
!request.url.host.contains("analytics") &&
234
!request.url.pathSegments.contains("ping")
235
}
236
}
237
}
238
```
239
240
#### Web/JavaScript Optimizations
241
```kotlin
242
val client = HttpClient {
243
install(Logging) {
244
logger = Logger.DEFAULT // Console logging
245
246
// Minimal logging for production builds
247
level = when (js("process.env.NODE_ENV")) {
248
"production" -> LogLevel.NONE
249
"development" -> LogLevel.ALL
250
else -> LogLevel.INFO
251
}
252
}
253
}
254
```
255
256
## Cross-Platform Compatibility
257
258
### Unified API
259
260
All platform-specific features maintain the same API surface:
261
262
```kotlin
263
// This code works identically across all platforms
264
class ApiClient {
265
private val client = HttpClient {
266
install(Logging) {
267
logger = Logger.DEFAULT // Platform-appropriate implementation
268
level = LogLevel.HEADERS
269
format = LoggingFormat.OkHttp
270
271
filter { request ->
272
request.url.host == "api.myapp.com"
273
}
274
275
sanitizeHeader { headerName ->
276
headerName.equals("Authorization", ignoreCase = true)
277
}
278
}
279
}
280
281
suspend fun fetchUser(id: String): User {
282
return client.get("https://api.myapp.com/users/$id").body()
283
}
284
}
285
```
286
287
### Platform Detection Example
288
289
```kotlin
290
val platformOptimizedClient = HttpClient {
291
install(Logging) {
292
// Platform-specific logger selection
293
logger = when (Platform.Current) {
294
is JvmPlatform -> if (isAndroid()) Logger.ANDROID else Logger.DEFAULT
295
is JsPlatform -> Logger.SIMPLE
296
is NativePlatform -> Logger.SIMPLE
297
}
298
299
// Platform-appropriate log levels
300
level = when (Platform.Current) {
301
is JvmPlatform -> LogLevel.ALL // JVM can handle verbose logging
302
else -> LogLevel.INFO // Mobile/web prefer less verbose
303
}
304
305
format = LoggingFormat.OkHttp // Compact format for all platforms
306
}
307
}
308
```
309
310
## Performance Considerations
311
312
### JVM Platform
313
- **SLF4J Overhead**: Minimal, delegates to configured logging framework
314
- **MDC Context**: Small overhead for context propagation
315
- **Message Limiting**: Optional, use only when needed
316
317
### Mobile Platforms
318
- **Battery Impact**: Use conservative log levels in production
319
- **Memory Usage**: Avoid `LogLevel.ALL` with large payloads
320
- **Performance**: Filter requests to reduce logging overhead
321
322
### Web Platforms
323
- **Bundle Size**: Logging adds minimal size overhead
324
- **Network Performance**: Consider filtering frequent requests
325
- **Development vs Production**: Use conditional logging levels