Skip to content
Bluetape4k docs1.11

Kotlin Logging and MDC

Latest stable Based on Bluetape4k release 1.11.0

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.

Responsibility map for logger creation, lazy messages, MDC, and asynchronous delivery

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.

RequirementDefault choiceBoundary to verify
Class or companion loggerKLoggingThe logger initializes on first access.
Top-level or explicit nameKotlinLogging.loggerBlank names are rejected.
Expensive messagelambda debug {} and peersDisabled levels do not evaluate the supplier.
Correlation context in synchronous codewithLoggingContextChoose nested-value restoration policy.
Correlation context in suspend codewithCoroutineLoggingContextMDCContext bridges dispatcher switches.
Decouple caller from emissionKLoggingChannelOwn 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.

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.

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.

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.

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.

The module integrates SLF4J providers, MDCContext from kotlinx-coroutines-slf4j, and Ktor or Spring request lifecycles. It does not create traces or metrics.

The host application owns levels, encoders, appenders, destinations, retention, and MDC output patterns. Keep exactly one provider on the runtime classpath.

Supplier failure becomes fallback text. MDC restoration runs in finally. Channel close cancels rather than drains, and events after close are dropped.

Observe fallback messages, duplicate providers or appenders, missing MDC fields, appender latency, and channel shutdown omissions. Remove secrets before they enter suppliers or MDC.

Terminal window
./gradlew :bluetape4k-logging:test --no-configuration-cache

Representative tests cover naming, level guards, supplier failure, nested MDC, coroutine propagation, and channel close.

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.

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.

  1. Logger foundation — names and provider boundary
  2. Lazy messages — level guards and supplier failure
  3. Scoped MDC — nested restoration and exceptional cleanup
  4. Coroutine MDC — suspension and child propagation
  5. Async channel — buffer, collector, close, and event loss
  6. Operations & recipes — configuration, redaction, diagnosis, and tests

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.

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”

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”

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”

KLoggingChannel async logging sequence with SharedFlow buffering and background collector emission

Release README: bluetape4k/logging/README.md