Struct opentelemetry_api::Context
source · pub struct Context { /* private fields */ }
Expand description
An execution-scoped collection of values.
A Context
is a propagation mechanism which carries execution-scoped
values across API boundaries and between logically associated execution
units. Cross-cutting concerns access their data in-process using the same
shared context object.
Context
s are immutable, and their write operations result in the creation
of a new context containing the original values and the new specified values.
Context state
Concerns can create and retrieve their local state in the current execution
state represented by a context through the get
and with_value
methods. It is recommended to use application-specific types when storing new
context values to avoid unintentionally overwriting existing state.
Managing the current context
Contexts can be associated with the caller’s current execution unit on a
given thread via the attach
method, and previous contexts can be restored
by dropping the returned ContextGuard
. Context can be nested, and will
restore their parent outer context when detached on drop. To access the
values of the context, a snapshot can be created via the Context::current
method.
Examples
use opentelemetry_api::Context;
// Application-specific `a` and `b` values
#[derive(Debug, PartialEq)]
struct ValueA(&'static str);
#[derive(Debug, PartialEq)]
struct ValueB(u64);
let _outer_guard = Context::new().with_value(ValueA("a")).attach();
// Only value a has been set
let current = Context::current();
assert_eq!(current.get::<ValueA>(), Some(&ValueA("a")));
assert_eq!(current.get::<ValueB>(), None);
{
let _inner_guard = Context::current_with_value(ValueB(42)).attach();
// Both values are set in inner context
let current = Context::current();
assert_eq!(current.get::<ValueA>(), Some(&ValueA("a")));
assert_eq!(current.get::<ValueB>(), Some(&ValueB(42)));
}
// Resets to only the `a` value when inner guard is dropped
let current = Context::current();
assert_eq!(current.get::<ValueA>(), Some(&ValueA("a")));
assert_eq!(current.get::<ValueB>(), None);
Implementations§
source§impl Context
impl Context
sourcepub fn new() -> Self
pub fn new() -> Self
Creates an empty Context
.
The context is initially created with a capacity of 0, so it will not
allocate. Use with_value
to create a new context that has entries.
sourcepub fn current() -> Self
pub fn current() -> Self
Returns an immutable snapshot of the current thread’s context.
Examples
use opentelemetry_api::Context;
#[derive(Debug, PartialEq)]
struct ValueA(&'static str);
fn do_work() {
assert_eq!(Context::current().get(), Some(&ValueA("a")));
}
let _guard = Context::new().with_value(ValueA("a")).attach();
do_work()
sourcepub fn map_current<T>(f: impl FnOnce(&Context) -> T) -> T
pub fn map_current<T>(f: impl FnOnce(&Context) -> T) -> T
Applys a function to the current context returning its value.
This can be used to build higher performing algebraic expressions for optionally creating a new context without the overhead of cloning the current one and dropping it.
Note: This function will panic if you attempt to attach another context while the current one is still borrowed.
sourcepub fn current_with_value<T: 'static + Send + Sync>(value: T) -> Self
pub fn current_with_value<T: 'static + Send + Sync>(value: T) -> Self
Returns a clone of the current thread’s context with the given value.
This is a more efficient form of Context::current().with_value(value)
as it avoids the intermediate context clone.
Examples
use opentelemetry_api::Context;
// Given some value types defined in your application
#[derive(Debug, PartialEq)]
struct ValueA(&'static str);
#[derive(Debug, PartialEq)]
struct ValueB(u64);
// You can create and attach context with the first value set to "a"
let _guard = Context::new().with_value(ValueA("a")).attach();
// And create another context based on the fist with a new value
let all_current_and_b = Context::current_with_value(ValueB(42));
// The second context now contains all the current values and the addition
assert_eq!(all_current_and_b.get::<ValueA>(), Some(&ValueA("a")));
assert_eq!(all_current_and_b.get::<ValueB>(), Some(&ValueB(42)));
sourcepub fn get<T: 'static>(&self) -> Option<&T>
pub fn get<T: 'static>(&self) -> Option<&T>
Returns a reference to the entry for the corresponding value type.
Examples
use opentelemetry_api::Context;
// Given some value types defined in your application
#[derive(Debug, PartialEq)]
struct ValueA(&'static str);
#[derive(Debug, PartialEq)]
struct MyUser();
let cx = Context::new().with_value(ValueA("a"));
// Values can be queried by type
assert_eq!(cx.get::<ValueA>(), Some(&ValueA("a")));
// And return none if not yet set
assert_eq!(cx.get::<MyUser>(), None);
sourcepub fn with_value<T: 'static + Send + Sync>(&self, value: T) -> Self
pub fn with_value<T: 'static + Send + Sync>(&self, value: T) -> Self
Returns a copy of the context with the new value included.
Examples
use opentelemetry_api::Context;
// Given some value types defined in your application
#[derive(Debug, PartialEq)]
struct ValueA(&'static str);
#[derive(Debug, PartialEq)]
struct ValueB(u64);
// You can create a context with the first value set to "a"
let cx_with_a = Context::new().with_value(ValueA("a"));
// And create another context based on the fist with a new value
let cx_with_a_and_b = cx_with_a.with_value(ValueB(42));
// The first context is still available and unmodified
assert_eq!(cx_with_a.get::<ValueA>(), Some(&ValueA("a")));
assert_eq!(cx_with_a.get::<ValueB>(), None);
// The second context now contains both values
assert_eq!(cx_with_a_and_b.get::<ValueA>(), Some(&ValueA("a")));
assert_eq!(cx_with_a_and_b.get::<ValueB>(), Some(&ValueB(42)));
sourcepub fn attach(self) -> ContextGuard
pub fn attach(self) -> ContextGuard
Replaces the current context on this thread with this context.
Dropping the returned ContextGuard
will reset the current context to the
previous value.
Examples
use opentelemetry_api::Context;
#[derive(Debug, PartialEq)]
struct ValueA(&'static str);
let my_cx = Context::new().with_value(ValueA("a"));
// Set the current thread context
let cx_guard = my_cx.attach();
assert_eq!(Context::current().get::<ValueA>(), Some(&ValueA("a")));
// Drop the guard to restore the previous context
drop(cx_guard);
assert_eq!(Context::current().get::<ValueA>(), None);
Guards do not need to be explicitly dropped:
use opentelemetry_api::Context;
#[derive(Debug, PartialEq)]
struct ValueA(&'static str);
fn my_function() -> String {
// attach a context the duration of this function.
let my_cx = Context::new().with_value(ValueA("a"));
// NOTE: a variable name after the underscore is **required** or rust
// will drop the guard, restoring the previous context _immediately_.
let _guard = my_cx.attach();
// anything happening in functions we call can still access my_cx...
my_other_function();
// returning from the function drops the guard, exiting the span.
return "Hello world".to_owned();
}
fn my_other_function() {
// ...
}
Sub-scopes may be created to limit the duration for which the span is entered:
use opentelemetry_api::Context;
#[derive(Debug, PartialEq)]
struct ValueA(&'static str);
let my_cx = Context::new().with_value(ValueA("a"));
{
let _guard = my_cx.attach();
// the current context can access variables in
assert_eq!(Context::current().get::<ValueA>(), Some(&ValueA("a")));
// exiting the scope drops the guard, detaching the context.
}
// this is back in the default empty context
assert_eq!(Context::current().get::<ValueA>(), None);