withLoggingContext

inline fun <ReturnT> withLoggingContext(vararg logFields: LogField, block: () -> ReturnT): ReturnT(source)
inline fun <ReturnT> withLoggingContext(logFields: List<LogField>, block: () -> ReturnT): ReturnT(source)

Adds the given log fields to every log made by a Logger in the context of the given block. Use the field/rawJsonField functions to construct log fields.

An example of when this is useful is when processing an event, and you want the event to be attached to every log while processing it. Instead of manually attaching the event to each log, you can wrap the event processing in withLoggingContext with the event as a log field, and then all logs inside that context will include the event.

Field value encoding with SLF4J

The JVM implementation uses MDC from SLF4J, which only supports String values by default. To encode object values as actual JSON (not escaped strings), you can add dev.hermannm.devlog.LoggingContextJsonFieldWriter as an mdcEntryWriter for logstash-logback-encoder, like this:

<!-- Example Logback config (in src/main/resources/logback.xml) -->
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<!-- Writes object values from logging context as actual JSON (not escaped) -->
<mdcEntryWriter class="dev.hermannm.devlog.LoggingContextJsonFieldWriter"/>
</encoder>
</appender>

<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration

This requires that you have added ch.qos.logback:logback-classic and net.logstash.logback:logstash-logback-encoder as dependencies.

Note on coroutines

SLF4J's MDC uses a thread-local, so it won't work by default with Kotlin coroutines and suspend functions. If you use coroutines, you can solve this with MDCContext from kotlinx-coroutines-slf4j.

Example

import dev.hermannm.devlog.field
import dev.hermannm.devlog.getLogger
import dev.hermannm.devlog.withLoggingContext

private val log = getLogger()

fun example(event: Event) {
withLoggingContext(field("event", event)) {
log.debug { "Started processing event" }
// ...
log.debug { "Finished processing event" }
}
}

If you have configured dev.hermannm.devlog.LoggingContextJsonFieldWriter, the field from withLoggingContext will then be attached to every log as follows:

{ "message": "Started processing event", "event": { ... } }
{ "message": "Finished processing event", "event": { ... } }