Interface Context
A Context object can be set to the ContextStorage, which
effectively forms a scope for the context. The scope is bound to the current thread.
Within a scope, its Context is accessible even across API boundaries, through current().
The scope is later exited by Scope.close() closing} the scope.
Context objects are immutable and inherit state from their parent. To add or overwrite the current state a new context object must be created and then attached, replacing the previously bound context. For example:
Context withCredential = Context.current().with(CRED_KEY, cred);
withCredential.wrap(new Runnable() {
public void run() {
readUserRecords(userId, CRED_KEY.get());
}
}).run();
Notes and cautions on use:
- Every
makeCurrent()must be followed by aScope.close(). Breaking these rules may lead to memory leaks and incorrect scoping. - While Context objects are immutable they do not place such a restriction on the state they store.
- Context is not intended for passing optional parameters to an API and developers should take care to avoid excessive dependence on context when designing an API.
- Attaching Context from a different ancestor will cause information in the current Context to be lost. This should generally be avoided.
Context propagation is not trivial, and when done incorrectly can lead to broken traces or
even mixed traces. We provide a debug mechanism for context propagation, which can be enabled by
setting -Dio.opentelemetry.context.enableStrictContext=true in your JVM args. This will
enable a strict checker that makes sure that Scopes are closed on the correct thread and
that they are not garbage collected before being closed. This is done with some relatively
expensive stack trace walking. It is highly recommended to enable this in unit tests and staging
environments, and you may consider enabling it in production if you have the CPU budget or have
very strict requirements on context being propagated correctly (i.e., because you use context in
a multi-tenant system). For kotlin coroutine users, this will also detect invalid usage of makeCurrent() from coroutines and suspending functions. This detection relies on internal APIs
of kotlin coroutines and may not function across all versions - let us know if you find a version
of kotlin coroutines where this mechanism does not function.
- See Also:
-
StrictContextStorage
-
Method Summary
Modifier and TypeMethodDescriptionstatic Contextcurrent()Return the context associated with the currentScope.<V> Vget(ContextKey<V> key) Returns the value stored in thisContextfor the givenContextKey, ornullif there is no value for the key in this context.default ScopeMakes this the current context and returns aScopewhich corresponds to the scope of execution this context is current for.static Contextroot()static ExecutortaskWrapping(Executor executor) Returns anExecutorwhich delegates to the providedexecutor, wrapping all invocations ofExecutor.execute(Runnable)with the current context at the time of invocation.static ExecutorServicetaskWrapping(ExecutorService executorService) Returns anExecutorServicewhich delegates to the providedexecutorService, wrapping all invocations ofExecutorServicemethods such asExecutor.execute(Runnable)orExecutorService.submit(Runnable)with the current context at the time of invocation.static ScheduledExecutorServicetaskWrapping(ScheduledExecutorService executorService) Returns anScheduledExecutorServicewhich delegates to the providedexecutorService, wrapping all invocations ofExecutorServicemethods such asExecutor.execute(Runnable)orExecutorService.submit(Runnable)with the current context at the time of invocation.<V> Contextwith(ContextKey<V> k1, V v1) Returns a new context with the given key value set.default Contextwith(ImplicitContextKeyed value) Returns a newContextwith the givenImplicitContextKeyedset.default Runnabledefault <T> Callable<T>default ExecutorReturns anExecutorthat will execute callbacks in the givenexecutor, making this the current context before each execution.default ExecutorServicewrap(ExecutorService executor) Returns anExecutorServicethat will execute callbacks in the givenexecutor, making this the current context before each execution.default ScheduledExecutorServicewrap(ScheduledExecutorService executor) Returns anScheduledExecutorServicethat will execute callbacks in the givenexecutor, making this the current context before each execution.default <T,U> BiConsumer<T, U> wrapConsumer(BiConsumer<T, U> consumer) default <T> Consumer<T>wrapConsumer(Consumer<T> consumer) default <T,U, V> BiFunction<T, U, V> wrapFunction(BiFunction<T, U, V> function) default <T,U> Function<T, U> wrapFunction(Function<T, U> function) default <T> Supplier<T>wrapSupplier(Supplier<T> supplier)
-
Method Details
-
current
Return the context associated with the currentScope. -
root
Returns the rootContextwhich all otherContextare derived from.It should generally not be required to use the root
Contextdirectly - instead, usecurrent()to operate on the currentContext. Only use this method if you are absolutely sure you need to disregard the currentContext- this almost always is only a workaround hiding an underlying context propagation issue. -
taskWrapping
Returns anExecutorwhich delegates to the providedexecutor, wrapping all invocations ofExecutor.execute(Runnable)with the current context at the time of invocation.This is generally used to create an
Executorwhich will forward theContextduring an invocation to another thread. For example, you may use something likeExecutor dbExecutor = Context.wrapTasks(threadPool)to ensure calls likedbExecutor.execute(() -> database.query())haveContextavailable on the thread executing database queries.- Since:
- 1.1.0
-
taskWrapping
Returns anExecutorServicewhich delegates to the providedexecutorService, wrapping all invocations ofExecutorServicemethods such asExecutor.execute(Runnable)orExecutorService.submit(Runnable)with the current context at the time of invocation.This is generally used to create an
ExecutorServicewhich will forward theContextduring an invocation to another thread. For example, you may use something likeExecutorService dbExecutor = Context.wrapTasks(threadPool)to ensure calls likedbExecutor.execute(() -> database.query())haveContextavailable on the thread executing database queries.- Since:
- 1.1.0
-
taskWrapping
Returns anScheduledExecutorServicewhich delegates to the providedexecutorService, wrapping all invocations ofExecutorServicemethods such asExecutor.execute(Runnable)orExecutorService.submit(Runnable)with the current context at the time of invocation.This is generally used to create an
ScheduledExecutorServicewhich will forward theContextduring an invocation to another thread. For example, you may use something likeScheduledExecutorService dbExecutor = Context.wrapTasks(threadPool)to ensure calls likedbExecutor.execute(() -> database.query())haveContextavailable on the thread executing database queries.Note: The context will not be propagated for
ScheduledExecutorService.scheduleAtFixedRate(Runnable, long, long, TimeUnit)andScheduledExecutorService.scheduleWithFixedDelay(Runnable, long, long, TimeUnit)calls.- Since:
- 1.43.0
-
get
Returns the value stored in thisContextfor the givenContextKey, ornullif there is no value for the key in this context. -
with
Returns a new context with the given key value set.Context withCredential = Context.current().with(CRED_KEY, cred); withCredential.wrap(new Runnable() { public void run() { readUserRecords(userId, CRED_KEY.get()); } }).run();Note that multiple calls to
with(ContextKey, Object)can be chained together.context.with(K1, V1).with(K2, V2);Nonetheless,
Contextshould not be treated like a general purpose map with a large number of keys and values — combine multiple related items together into a single key instead of separating them. But if the items are unrelated, have separate keys for them. -
with
Returns a newContextwith the givenImplicitContextKeyedset. -
makeCurrent
Makes this the current context and returns aScopewhich corresponds to the scope of execution this context is current for.current()will return thisContextuntilScope.close()is called.Scope.close()must be called to properly restore the previous context from before this scope of execution or context will not work correctly. It is recommended to use try-with-resources to callScope.close()automatically.The default implementation of this method will store the
Contextin aThreadLocal. Kotlin coroutine users SHOULD NOT use this method as theThreadLocalwill not be properly synced across coroutine suspension and resumption. Instead, usewithContext(context.asContextElement())provided by theopentelemetry-extension-kotlinlibrary.Context prevCtx = Context.current(); try (Scope ignored = ctx.makeCurrent()) { assert Context.current() == ctx; ... } assert Context.current() == prevCtx; -
wrap
-
wrap
-
wrap
Returns anExecutorthat will execute callbacks in the givenexecutor, making this the current context before each execution. -
wrap
Returns anExecutorServicethat will execute callbacks in the givenexecutor, making this the current context before each execution. -
wrap
Returns anScheduledExecutorServicethat will execute callbacks in the givenexecutor, making this the current context before each execution. -
wrapFunction
-
wrapFunction
-
wrapConsumer
-
wrapConsumer
-
wrapSupplier
-