1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! The trace context a call or an event can carry.
//!
//! [`TraceContext`] is the W3C Trace Context `traceparent` layout without the
//! version byte, as plain data. `ridl-rt` carries it unvalidated: an all-zero
//! id is carried like any other value, and rejecting one is the choice of
//! whatever exports the trace.
//!
//! With the `std` feature, [`Propagation`] is the hook through which an
//! application gives generated code the context to send and receives the
//! context that arrived.
/// A trace id, a span id and the trace flags, in the layout of the W3C Trace
/// Context `traceparent` header without its version byte.
///
/// The value is not validated. `size_of::<TraceContext>()` is 25 bytes and
/// `size_of::<Option<TraceContext>>()` is 26 bytes, both with alignment 1.
use OnceLock;
/// The hook through which an application connects its telemetry library to the
/// trace context that crosses a port. Available with the `std` feature.
///
/// `ridl-rt` carries the bytes. The code that a generated crate emits is meant
/// to call the hook at the points below. No generated code calls it yet: the
/// generated face still passes `None` as the trace context (driftsys/ridl#754
/// tracks the change). Which span is current, how ids are created and where traces are
/// exported belong to the application's library. No hook is registered until
/// the application calls [`set_propagation`].
///
/// # Call points
///
/// Generated code that calls the hook calls:
///
/// - [`current`](Propagation::current) just before it sends a call or a raise.
/// It returns the context to send, or `None`.
/// - [`enter`](Propagation::enter) when it receives a claim, before the claim
/// span exists and before the handler runs.
/// - [`leave`](Propagation::leave) after the handler has returned, and also
/// when the handler panics.
///
/// # Call order for a claim
///
/// Generated code that serves a claim and calls the hook follows this order:
///
/// 1. `enter(received)`, where `received` is the context that came over the
/// wire. It is `None` for a claim that carried no context, and `leave` is
/// still called to pair with that `enter`.
/// 2. The claim span is created with no explicit parent, and entered.
/// 3. The handler runs.
/// 4. The claim span is exited and dropped.
/// 5. `leave()`.
///
/// An OpenTelemetry implementation of `enter` attaches a context that carries
/// the received span context as a remote parent, keeps the guard, and drops
/// the guard in `leave`. It relies on `tracing-opentelemetry` choosing the
/// parent of a span when the span is created, from the attached context. That
/// context activation is on by default since `tracing-opentelemetry` 0.32.0.
/// Setting the parent after the claim span is entered fails, because entering
/// the span starts it.
///
/// The guard that calls `leave` is created only after `enter` returns, so a
/// panic inside `enter` does not call `leave`. An implementation's `enter` and
/// `leave` should not panic: a panic in `leave` while another panic unwinds
/// aborts the process, and a panic in `enter` leaves nothing attached.
///
/// # Nesting and threads
///
/// Each `enter` is paired with one `leave`. Pairs nest: a handler that serves
/// another claim produces an inner pair inside the outer one. The `leave` of a
/// pair runs on the thread that ran its `enter`, so an implementation can keep
/// what `enter` attached on a per-thread stack.
/// [`set_propagation`] was called after a hook was already registered.
;
static HOOK: = new;
/// Registers the hook once for the process, as `log::set_logger` does for the
/// `log` crate. A second call returns [`AlreadySet`] and keeps the first hook.
///
/// One hook serves every generated crate in the process, so a handler in one
/// generated crate that calls a client of another continues the same trace.
/// The registered hook, or `None` while the application has not called
/// [`set_propagation`].