Kotlin Logging and MDC
Latest stable Based on Bluetape4k release 1.11.0
Problem
Section titled “Problem”bluetape4k-logging treats logging as more than a call syntax: when is a message evaluated, how far does request context travel, and who closes asynchronous delivery? The application still owns the SLF4J provider and appenders.
When to use
Section titled “When to use”Use it for consistent logger naming, lazy messages, and correlation context scoped to an operation. Do not add wrappers when plain SLF4J already expresses the complete contract.
API by task
Section titled “API by task”| Requirement | Default choice | Boundary to verify |
|---|---|---|
| Class or companion logger | KLogging | The logger initializes on first access. |
| Top-level or explicit name | KotlinLogging.logger | Blank names are rejected. |
| Expensive message | lambda debug {} and peers | Disabled levels do not evaluate the supplier. |
| Correlation context in synchronous code | withLoggingContext | Choose nested-value restoration policy. |
| Correlation context in suspend code | withCoroutineLoggingContext | MDCContext bridges dispatcher switches. |
| Decouple caller from emission | KLoggingChannel | Own buffering, collection, close, and possible loss. |
Start ordinary services with KLogging and scoped MDC. Choose KLoggingChannel only after synchronous appenders are measured as a bottleneck and shutdown handling for pending events is explicit.
Coordinates
Section titled “Coordinates”dependencies { implementation(platform("io.github.bluetape4k:bluetape4k-dependencies:<version>")) implementation("io.github.bluetape4k:bluetape4k-logging") runtimeOnly("ch.qos.logback:logback-classic:<version>")}Select exactly one SLF4J provider in the application. This module does not configure levels, encoders, destinations, or retention.
Concepts
Section titled “Concepts”Logger creation, lazy event construction, MDC context, and optional background delivery are separate responsibilities. This prevents provider policy and channel lifecycle from hiding inside a convenience helper.
Quick start
Section titled “Quick start”class OrderService { companion object : KLogging()
suspend fun load(orderId: String): Order = withCoroutineLoggingContext("orderId" to orderId) { log.debug { "Loading order" } repository.load(orderId) }}The message lambda runs only when DEBUG is enabled. orderId travels with the coroutine context and is restored when the scope ends.
Patterns
Section titled “Patterns”Sanitize correlation keys at the transport boundary and keep them around the smallest owning operation. A message supplier should compute a value without introducing side effects.
Integrations
Section titled “Integrations”The module integrates SLF4J providers, MDCContext from kotlinx-coroutines-slf4j, and Ktor or Spring request lifecycles. It does not create traces or metrics.
Configuration
Section titled “Configuration”The host application owns levels, encoders, appenders, destinations, retention, and MDC output patterns. Keep exactly one provider on the runtime classpath.
Failures
Section titled “Failures”Supplier failure becomes fallback text. MDC restoration runs in finally. Channel close cancels rather than drains, and events after close are dropped.
Operations
Section titled “Operations”Observe fallback messages, duplicate providers or appenders, missing MDC fields, appender latency, and channel shutdown omissions. Remove secrets before they enter suppliers or MDC.
Testing
Section titled “Testing”./gradlew :bluetape4k-logging:test --no-configuration-cacheRepresentative tests cover naming, level guards, supplier failure, nested MDC, coroutine propagation, and channel close.
Workshops
Section titled “Workshops”No dedicated logging workshop is registered. The smallest exercise applies correlation context at a Ktor or Spring request boundary and tests nested restoration plus shutdown.
Limitations
Section titled “Limitations”Logging is not tracing, audit storage, or durable event delivery. MDC cannot follow thread switches without a bridge, and the async channel does not guarantee pending events at shutdown.
Learning path
Section titled “Learning path”- Logger foundation — names and provider boundary
- Lazy messages — level guards and supplier failure
- Scoped MDC — nested restoration and exceptional cleanup
- Coroutine MDC — suspension and child propagation
- Async channel — buffer, collector, close, and event loss
- Operations & recipes — configuration, redaction, diagnosis, and tests
Contract boundary
Section titled “Contract boundary”The manual promotes only behavior verified in current source and representative tests: naming, lazy evaluation, fallback messages, MDC restore/remove, the coroutine bridge, and channel close behavior. README timing examples are not controlled benchmarks and are not library guarantees.
Release diagrams
Section titled “Release diagrams”These diagrams are loaded directly from README assets published with the 1.11.0 release and pinned to its immutable commit. They describe this manual’s released structure and runtime flows, not later Snapshot changes. Select a preview to open the SVG at the same release commit.
Logging class structure for KLogging, KotlinLogging, MDC helpers, and async channel logging
Section titled “Logging class structure for KLogging, KotlinLogging, MDC helpers, and async channel logging”Release README: bluetape4k/logging/README.md
Logging processing flow for level guards, lazy message suppliers, MDC context, and SLF4J emission
Section titled “Logging processing flow for level guards, lazy message suppliers, MDC context, and SLF4J emission”Release README: bluetape4k/logging/README.md
KLoggingChannel async logging sequence with SharedFlow buffering and background collector emission
Section titled “KLoggingChannel async logging sequence with SharedFlow buffering and background collector emission”Release README: bluetape4k/logging/README.md


