1#![deny(missing_docs, missing_debug_implementations)]
8
9#[cfg(feature = "opentelemetry")]
20use opentelemetry::trace::TraceContextExt;
21use rand::Rng;
22use std::{
23 convert::TryFrom,
24 fmt::{self, Formatter},
25 num::{NonZeroU128, NonZeroU64},
26};
27#[cfg(feature = "opentelemetry")]
28use tracing_opentelemetry::OpenTelemetrySpanExt;
29
30#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Copy)]
35#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
36pub struct Context {
37 pub trace_id: TraceId,
40 pub span_id: SpanId,
44 pub sampling_decision: SamplingDecision,
52}
53
54#[derive(Default, PartialEq, Eq, Hash, Clone, Copy)]
57#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
58pub struct TraceId(#[cfg_attr(feature = "serde1", serde(with = "u128_serde"))] u128);
59
60#[derive(Default, PartialEq, Eq, Hash, Clone, Copy)]
62#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
63pub struct SpanId(u64);
64
65#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
72#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
73#[repr(u8)]
74pub enum SamplingDecision {
75 Sampled,
77 Unsampled,
79}
80
81impl Context {
82 pub(crate) fn new_child(&self) -> Self {
84 Self {
85 trace_id: self.trace_id,
86 span_id: SpanId::random(&mut rand::thread_rng()),
87 sampling_decision: self.sampling_decision,
88 }
89 }
90}
91
92impl TraceId {
93 pub fn random<R: Rng>(rng: &mut R) -> Self {
96 TraceId(rng.gen::<NonZeroU128>().get())
97 }
98
99 pub fn is_none(&self) -> bool {
101 self.0 == 0
102 }
103}
104
105impl SpanId {
106 pub fn random<R: Rng>(rng: &mut R) -> Self {
108 SpanId(rng.gen::<NonZeroU64>().get())
109 }
110
111 pub fn is_none(&self) -> bool {
113 self.0 == 0
114 }
115}
116
117impl From<TraceId> for u128 {
118 fn from(trace_id: TraceId) -> Self {
119 trace_id.0
120 }
121}
122
123impl From<u128> for TraceId {
124 fn from(trace_id: u128) -> Self {
125 Self(trace_id)
126 }
127}
128
129impl From<SpanId> for u64 {
130 fn from(span_id: SpanId) -> Self {
131 span_id.0
132 }
133}
134
135impl From<u64> for SpanId {
136 fn from(span_id: u64) -> Self {
137 Self(span_id)
138 }
139}
140
141#[cfg(feature = "opentelemetry")]
142impl From<opentelemetry::trace::TraceId> for TraceId {
143 fn from(trace_id: opentelemetry::trace::TraceId) -> Self {
144 Self::from(u128::from_be_bytes(trace_id.to_bytes()))
145 }
146}
147#[cfg(feature = "opentelemetry")]
148impl From<TraceId> for opentelemetry::trace::TraceId {
149 fn from(trace_id: TraceId) -> Self {
150 Self::from_bytes(u128::from(trace_id).to_be_bytes())
151 }
152}
153#[cfg(feature = "opentelemetry")]
154impl From<opentelemetry::trace::SpanId> for SpanId {
155 fn from(span_id: opentelemetry::trace::SpanId) -> Self {
156 Self::from(u64::from_be_bytes(span_id.to_bytes()))
157 }
158}
159#[cfg(feature = "opentelemetry")]
160impl From<SpanId> for opentelemetry::trace::SpanId {
161 fn from(span_id: SpanId) -> Self {
162 Self::from_bytes(u64::from(span_id).to_be_bytes())
163 }
164}
165
166impl TryFrom<&tracing::Span> for Context {
167 type Error = NoActiveSpan;
168 #[cfg(feature = "opentelemetry")]
169 fn try_from(span: &tracing::Span) -> Result<Self, NoActiveSpan> {
170 let context = span.context();
171 if context.has_active_span() {
172 Ok(Self::from(context.span()))
173 } else {
174 Err(NoActiveSpan)
175 }
176 }
177 #[cfg(not(feature = "opentelemetry"))]
178 fn try_from(_span: &tracing::Span) -> Result<Self, NoActiveSpan> {
179 Err(NoActiveSpan)
180 }
181}
182
183#[cfg(feature = "opentelemetry")]
184impl From<opentelemetry::trace::SpanRef<'_>> for Context {
185 fn from(span: opentelemetry::trace::SpanRef<'_>) -> Self {
186 let otel_ctx = span.span_context();
187 Self {
188 trace_id: TraceId::from(otel_ctx.trace_id()),
189 span_id: SpanId::from(otel_ctx.span_id()),
190 sampling_decision: SamplingDecision::from(otel_ctx),
191 }
192 }
193}
194#[cfg(feature = "opentelemetry")]
195impl From<SamplingDecision> for opentelemetry::trace::TraceFlags {
196 fn from(decision: SamplingDecision) -> Self {
197 match decision {
198 SamplingDecision::Sampled => opentelemetry::trace::TraceFlags::SAMPLED,
199 SamplingDecision::Unsampled => opentelemetry::trace::TraceFlags::default(),
200 }
201 }
202}
203#[cfg(feature = "opentelemetry")]
204impl From<&opentelemetry::trace::SpanContext> for SamplingDecision {
205 fn from(context: &opentelemetry::trace::SpanContext) -> Self {
206 if context.is_sampled() {
207 SamplingDecision::Sampled
208 } else {
209 SamplingDecision::Unsampled
210 }
211 }
212}
213
214impl Default for SamplingDecision {
215 fn default() -> Self {
216 Self::Unsampled
217 }
218}
219
220#[derive(Debug)]
222pub struct NoActiveSpan;
223
224impl fmt::Display for TraceId {
225 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
226 write!(f, "{:02x}", self.0)?;
227 Ok(())
228 }
229}
230
231impl fmt::Debug for TraceId {
232 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
233 write!(f, "{:02x}", self.0)?;
234 Ok(())
235 }
236}
237
238impl fmt::Display for SpanId {
239 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
240 write!(f, "{:02x}", self.0)?;
241 Ok(())
242 }
243}
244
245impl fmt::Debug for SpanId {
246 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
247 write!(f, "{:02x}", self.0)?;
248 Ok(())
249 }
250}
251
252#[cfg(feature = "serde1")]
253mod u128_serde {
254 pub fn serialize<S>(u: &u128, serializer: S) -> Result<S::Ok, S::Error>
255 where
256 S: serde::Serializer,
257 {
258 serde::Serialize::serialize(&u.to_le_bytes(), serializer)
259 }
260
261 pub fn deserialize<'de, D>(deserializer: D) -> Result<u128, D::Error>
262 where
263 D: serde::Deserializer<'de>,
264 {
265 Ok(u128::from_le_bytes(serde::Deserialize::deserialize(
266 deserializer,
267 )?))
268 }
269}