0
# Logging
1
2
Multi-level logging interface with lazy evaluation for performance optimization. Provides a flexible logging system with support for different log levels, structured logging, and platform-specific implementations.
3
4
## Capabilities
5
6
### Logger Interface
7
8
Core logging interface providing multiple log levels with lazy evaluation support.
9
10
```kotlin { .api }
11
/**
12
* Multi-level logging interface (expect/actual pattern for multiplatform)
13
*/
14
expect interface Logger {
15
/** Log trace level message */
16
fun trace(message: String)
17
18
/** Log trace level message with exception */
19
fun trace(message: String, cause: Throwable)
20
21
/** Log debug level message */
22
fun debug(message: String)
23
24
/** Log debug level message with exception */
25
fun debug(message: String, cause: Throwable)
26
27
/** Log info level message */
28
fun info(message: String)
29
30
/** Log info level message with exception */
31
fun info(message: String, cause: Throwable)
32
33
/** Log warning level message */
34
fun warn(message: String)
35
36
/** Log warning level message with exception */
37
fun warn(message: String, cause: Throwable)
38
39
/** Log error level message */
40
fun error(message: String)
41
42
/** Log error level message with exception */
43
fun error(message: String, cause: Throwable)
44
}
45
46
/** Check if trace level is enabled */
47
expect val Logger.isTraceEnabled: Boolean
48
49
/** Check if debug level is enabled */
50
expect val Logger.isDebugEnabled: Boolean
51
52
/** Log error from exception using its message */
53
fun Logger.error(exception: Throwable)
54
```
55
56
**Usage Examples:**
57
58
```kotlin
59
import io.ktor.util.logging.*
60
61
val logger = KtorSimpleLogger("MyApp")
62
63
// Basic logging
64
logger.info("Application started")
65
logger.warn("Configuration not found, using defaults")
66
67
// Lazy evaluation for expensive operations
68
logger.debug { "Processing user data: ${expensiveUserDataCalculation()}" }
69
logger.trace { "Request details: ${request.toDetailedString()}" }
70
71
// Error logging with exceptions
72
try {
73
riskyOperation()
74
} catch (e: Exception) {
75
logger.error("Operation failed", e)
76
logger.error(e) { "Additional context: ${context.details}" }
77
}
78
```
79
80
### KtorSimpleLogger
81
82
Factory function for creating simple logger instances.
83
84
```kotlin { .api }
85
/**
86
* Create logger instance with name (expect/actual factory function)
87
* @param name Logger name (typically class or component name)
88
* @return Logger instance
89
*/
90
expect fun KtorSimpleLogger(name: String): Logger
91
```
92
93
**Usage Examples:**
94
95
```kotlin
96
import io.ktor.util.logging.*
97
98
// Create logger with default INFO level
99
val logger = KtorSimpleLogger("DatabaseService")
100
101
// Create logger with specific level
102
val debugLogger = KtorSimpleLogger("DebugComponent", LogLevel.DEBUG)
103
104
// Check if level is enabled before expensive operations
105
if (logger.isEnabled(LogLevel.DEBUG)) {
106
val debugInfo = collectDebugInformation()
107
logger.debug("Debug info: $debugInfo")
108
}
109
110
// Use different loggers for different components
111
class UserService {
112
private val logger = KtorSimpleLogger("UserService")
113
114
fun createUser(userData: UserData) {
115
logger.info("Creating user: ${userData.username}")
116
try {
117
// ... create user
118
logger.debug("User created successfully")
119
} catch (e: Exception) {
120
logger.error("Failed to create user", e)
121
throw e
122
}
123
}
124
}
125
```
126
127
### JVM Logger Factory
128
129
JVM-specific logger factory with integration for popular logging frameworks.
130
131
```kotlin { .api }
132
/**
133
* Factory for creating loggers on JVM platform
134
*/
135
object LoggerFactory {
136
/** Create logger with specified name */
137
fun getLogger(name: String): Logger
138
139
/** Create logger for specific class */
140
fun getLogger(clazz: Class<*>): Logger
141
142
/** Create logger with inline class reification */
143
inline fun <reified T> getLogger(): Logger
144
}
145
```
146
147
**Usage Examples:**
148
149
```kotlin
150
import io.ktor.util.logging.*
151
152
// Create loggers using factory
153
val serviceLogger = LoggerFactory.getLogger("UserService")
154
val classLogger = LoggerFactory.getLogger(DatabaseService::class.java)
155
156
// Create logger with reified type
157
class PaymentProcessor {
158
private val logger = LoggerFactory.getLogger<PaymentProcessor>()
159
160
fun processPayment(amount: Double) {
161
logger.info("Processing payment: $amount")
162
// ... payment logic
163
}
164
}
165
166
// Use in companion objects
167
class OrderService {
168
companion object {
169
private val logger = LoggerFactory.getLogger<OrderService>()
170
}
171
172
fun createOrder() {
173
logger.debug("Creating new order")
174
}
175
}
176
```
177
178
### Structured Logging
179
180
Enhanced logging capabilities with structured data support.
181
182
```kotlin { .api }
183
/**
184
* Structured logging with key-value pairs
185
*/
186
interface StructuredLogger : Logger {
187
/** Log with structured data */
188
fun info(message: String, vararg fields: Pair<String, Any?>)
189
fun debug(message: String, vararg fields: Pair<String, Any?>)
190
fun warn(message: String, vararg fields: Pair<String, Any?>)
191
fun error(message: String, exception: Throwable?, vararg fields: Pair<String, Any?>)
192
193
/** Create logger context with persistent fields */
194
fun withFields(vararg fields: Pair<String, Any?>): StructuredLogger
195
}
196
197
/**
198
* MDC (Mapped Diagnostic Context) utilities for request tracing
199
*/
200
object MDC {
201
/** Put value in diagnostic context */
202
fun put(key: String, value: String?)
203
204
/** Get value from diagnostic context */
205
fun get(key: String): String?
206
207
/** Remove value from diagnostic context */
208
fun remove(key: String)
209
210
/** Clear all diagnostic context */
211
fun clear()
212
213
/** Execute block with temporary MDC values */
214
fun <T> withContext(vararg pairs: Pair<String, String>, block: () -> T): T
215
}
216
```
217
218
**Usage Examples:**
219
220
```kotlin
221
import io.ktor.util.logging.*
222
223
// Structured logging
224
val structuredLogger: StructuredLogger = // ... implementation
225
226
structuredLogger.info(
227
"User login successful",
228
"userId" to 12345,
229
"username" to "alice",
230
"loginMethod" to "oauth2"
231
)
232
233
structuredLogger.error(
234
"Payment processing failed",
235
exception,
236
"orderId" to order.id,
237
"amount" to order.total,
238
"currency" to order.currency
239
)
240
241
// Logger with persistent context
242
val userLogger = structuredLogger.withFields(
243
"userId" to currentUser.id,
244
"sessionId" to currentSession.id
245
)
246
247
userLogger.info("User action performed", "action" to "profile_update")
248
249
// MDC for request tracing
250
MDC.withContext(
251
"requestId" to UUID.randomUUID().toString(),
252
"userId" to user.id.toString()
253
) {
254
logger.info("Processing user request")
255
processUserRequest()
256
logger.info("Request processing complete")
257
}
258
```
259
260
### Async Logging
261
262
Asynchronous logging capabilities for high-performance scenarios.
263
264
```kotlin { .api }
265
/**
266
* Asynchronous logger wrapper
267
*/
268
class AsyncLogger(
269
private val delegate: Logger,
270
private val bufferSize: Int = 1000,
271
private val flushInterval: Duration = 1.seconds
272
) : Logger {
273
/** Start async logging */
274
fun start()
275
276
/** Stop async logging and flush remaining messages */
277
suspend fun stop()
278
279
/** Force flush of buffered messages */
280
suspend fun flush()
281
}
282
283
/**
284
* Batched logging for high-throughput scenarios
285
*/
286
class BatchLogger(
287
private val delegate: Logger,
288
private val batchSize: Int = 100
289
) : Logger {
290
/** Flush current batch */
291
fun flushBatch()
292
}
293
```
294
295
**Usage Examples:**
296
297
```kotlin
298
import io.ktor.util.logging.*
299
import kotlinx.coroutines.*
300
301
// Async logging for high-performance applications
302
val baseLogger = KtorSimpleLogger("HighThroughputService")
303
val asyncLogger = AsyncLogger(baseLogger, bufferSize = 5000)
304
305
// Start async logging
306
asyncLogger.start()
307
308
// Log messages (buffered and written asynchronously)
309
repeat(10000) { i ->
310
asyncLogger.info("Processing item $i")
311
}
312
313
// Graceful shutdown
314
asyncLogger.stop()
315
316
// Batch logging for bulk operations
317
val batchLogger = BatchLogger(baseLogger, batchSize = 50)
318
319
repeat(1000) { i ->
320
batchLogger.debug("Batch item $i")
321
if (i % 50 == 0) {
322
batchLogger.flushBatch()
323
}
324
}
325
```
326
327
### Logging Configuration
328
329
Configuration utilities for logger setup and management.
330
331
```kotlin { .api }
332
/**
333
* Logger configuration builder
334
*/
335
class LoggerConfig {
336
/** Set default log level */
337
var defaultLevel: LogLevel = LogLevel.INFO
338
339
/** Set logger-specific levels */
340
fun level(loggerName: String, level: LogLevel)
341
342
/** Set output format */
343
var format: LogFormat = LogFormat.TEXT
344
345
/** Set output destination */
346
var output: LogOutput = LogOutput.CONSOLE
347
348
/** Apply configuration */
349
fun apply()
350
}
351
352
/**
353
* Log format options
354
*/
355
enum class LogFormat {
356
TEXT, JSON, STRUCTURED
357
}
358
359
/**
360
* Log output destinations
361
*/
362
enum class LogOutput {
363
CONSOLE, FILE, SYSLOG
364
}
365
```
366
367
**Usage Examples:**
368
369
```kotlin
370
import io.ktor.util.logging.*
371
372
// Configure logging system
373
val config = LoggerConfig().apply {
374
defaultLevel = LogLevel.DEBUG
375
level("io.ktor.server", LogLevel.INFO)
376
level("io.ktor.client", LogLevel.WARN)
377
format = LogFormat.JSON
378
output = LogOutput.FILE
379
}
380
config.apply()
381
382
// Use configured loggers
383
val logger = LoggerFactory.getLogger("MyApplication")
384
logger.debug("This will be logged based on configuration")
385
```
386
387
## Performance Considerations
388
389
- **Lazy Evaluation**: Use lambda-based logging methods for expensive message construction
390
- **Level Checking**: Check `isEnabled()` before expensive operations
391
- **Async Logging**: Use `AsyncLogger` for high-throughput scenarios
392
- **Structured Data**: Prefer structured logging over string concatenation
393
- **MDC Management**: Clear MDC contexts to prevent memory leaks