tarpc_trace/
lib.rs

1// Copyright 2018 Google LLC
2//
3// Use of this source code is governed by an MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT.
6
7#![deny(missing_docs, missing_debug_implementations)]
8
9//! Provides building blocks for tracing distributed programs.
10//!
11//! A trace is logically a tree of causally-related events called spans. Traces are tracked via a
12//! [context](Context) that identifies the current trace, span, and parent of the current span.  In
13//! distributed systems, a context can be sent from client to server to connect events occurring on
14//! either side.
15//!
16//! This crate's design is based on [opencensus
17//! tracing](https://opencensus.io/core-concepts/tracing/).
18
19use rand::Rng;
20use std::{
21    fmt::{self, Formatter},
22    mem,
23};
24
25/// A context for tracing the execution of processes, distributed or otherwise.
26///
27/// Consists of a span identifying an event, an optional parent span identifying a causal event
28/// that triggered the current span, and a trace with which all related spans are associated.
29#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Copy)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
31pub struct Context {
32    /// An identifier of the trace associated with the current context. A trace ID is typically
33    /// created at a root span and passed along through all causal events.
34    pub trace_id: TraceId,
35    /// An identifier of the current span. In typical RPC usage, a span is created by a client
36    /// before making an RPC, and the span ID is sent to the server. The server is free to create
37    /// its own spans, for which it sets the client's span as the parent span.
38    pub span_id: SpanId,
39    /// An identifier of the span that originated the current span. For example, if a server sends
40    /// an RPC in response to a client request that included a span, the server would create a span
41    /// for the RPC and set its parent to the span_id in the incoming request's context.
42    ///
43    /// If `parent_id` is `None`, then this is a root context.
44    pub parent_id: Option<SpanId>,
45}
46
47/// A 128-bit UUID identifying a trace. All spans caused by the same originating span share the
48/// same trace ID.
49#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Copy)]
50#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
51pub struct TraceId(u128);
52
53/// A 64-bit identifier of a span within a trace. The identifier is unique within the span's trace.
54#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Copy)]
55#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
56pub struct SpanId(u64);
57
58impl Context {
59    /// Constructs a new root context. A root context is one with no parent span.
60    pub fn new_root() -> Self {
61        let rng = &mut rand::thread_rng();
62        Context {
63            trace_id: TraceId::random(rng),
64            span_id: SpanId::random(rng),
65            parent_id: None,
66        }
67    }
68}
69
70impl TraceId {
71    /// Returns a random trace ID that can be assumed to be globally unique if `rng` generates
72    /// actually-random numbers.
73    pub fn random<R: Rng>(rng: &mut R) -> Self {
74        TraceId(u128::from(rng.next_u64()) << mem::size_of::<u64>() | u128::from(rng.next_u64()))
75    }
76}
77
78impl SpanId {
79    /// Returns a random span ID that can be assumed to be unique within a single trace.
80    pub fn random<R: Rng>(rng: &mut R) -> Self {
81        SpanId(rng.next_u64())
82    }
83}
84
85impl fmt::Display for TraceId {
86    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
87        write!(f, "{:02x}", self.0)?;
88        Ok(())
89    }
90}
91
92impl fmt::Display for SpanId {
93    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
94        write!(f, "{:02x}", self.0)?;
95        Ok(())
96    }
97}