Add PropagationContextElement Kotlin operator

Prior to this commit, the Micrometer context-propagation project would
help propagating information from `ThreadLocal`, Reactor `Context` and
other context objects. This is already well supported for Micrometer
Observations.

In the case of Kotlin suspending functions, the processing of tasks
would not necessarily update the `ThreadLocal` when the function is
scheduled on a different thread.

This commit introduces the `PropagationContextElement` operator that
connects the `ThreadLocal`, Reactor `Context` and Coroutine `Context`
for all libraries using the "context-propagation" project.

Applications must manually use this operator in suspending functions
like so:

```
suspend fun suspendingFunction() {
  return withContext(PropagationContextElement(currentCoroutineContext())) {
    logger.info("Suspending function with traceId")
  }
}
```

Closes gh-35185
This commit is contained in:
Brian Clozel
2025-09-09 21:42:08 +02:00
parent 21e52a4283
commit ef2a403df6
6 changed files with 246 additions and 0 deletions
@@ -250,3 +250,36 @@ For Kotlin `Flow`, a `Flow<T>.transactional` extension is provided.
}
}
----
[[coroutines.propagation]]
== Context Propagation
Spring applications are xref:integration/observability.adoc[instrumented with Micrometer for Observability support].
For tracing support, the current observation is propagated through a `ThreadLocal` for blocking code,
or the Reactor `Context` for reactive pipelines. But the current observation also needs to be made available
in the execution context of a suspended function. Without that, the current "traceId" will not be automatically prepended
to logged statements from coroutines.
The `org.springframework.core.PropagationContextElement` operator generally ensures that the
{micrometer-context-propagation-docs}/[Micrometer Context Propagation library] works with Kotlin Coroutines.
The `PropagationContextElement` requires the following dependencies:
`build.gradle.kts`
[source,kotlin,indent=0]
----
dependencies {
implementation("io.micrometer:context-propagation:${contextPropagationVersion}")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${coroutinesVersion}")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:${coroutinesVersion}")
}
----
Applications can then use the `PropagationContextElement` operator to connect the `currentCoroutineContext()`
with the context propagation mechanism:
include-code::./ContextPropagationSample[tag=context,indent=0]
Here, assuming that Micrometer Tracing is configured, the resulting logging statement
will show the current "traceId" and unlock better observability for your application.