Skip to main content

torrust_tracker_deployer_lib/domain/environment/
trace_id.rs

1//! Trace identifier for linking errors to trace files
2//!
3//! The `TraceId` provides a unique identifier for each error trace,
4//! enabling correlation between error contexts stored in state and
5//! detailed trace files.
6
7use serde::{Deserialize, Serialize};
8use uuid::Uuid;
9
10/// Unique identifier for error traces
11///
12/// Uses UUID v4 to ensure uniqueness across all environments and time periods.
13/// The newtype pattern provides type safety and prevents mixing trace IDs
14/// with other UUIDs in the system.
15///
16/// # Example
17///
18/// ```rust
19/// use torrust_tracker_deployer_lib::domain::environment::TraceId;
20///
21/// let trace_id = TraceId::new();
22/// println!("Trace ID: {}", trace_id);
23/// ```
24#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
25pub struct TraceId(Uuid);
26
27impl TraceId {
28    /// Generate a new unique trace identifier
29    ///
30    /// # Example
31    ///
32    /// ```rust
33    /// use torrust_tracker_deployer_lib::domain::environment::TraceId;
34    ///
35    /// let id1 = TraceId::new();
36    /// let id2 = TraceId::new();
37    /// assert_ne!(id1, id2);
38    /// ```
39    #[must_use]
40    pub fn new() -> Self {
41        Self(Uuid::new_v4())
42    }
43
44    /// Get the inner UUID value
45    ///
46    /// # Example
47    ///
48    /// ```rust
49    /// use torrust_tracker_deployer_lib::domain::environment::TraceId;
50    ///
51    /// let trace_id = TraceId::new();
52    /// let uuid = trace_id.inner();
53    /// println!("UUID: {}", uuid);
54    /// ```
55    #[must_use]
56    pub fn inner(&self) -> &Uuid {
57        &self.0
58    }
59}
60
61impl Default for TraceId {
62    fn default() -> Self {
63        Self::new()
64    }
65}
66
67impl std::fmt::Display for TraceId {
68    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        write!(f, "{}", self.0)
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn it_should_create_unique_trace_ids() {
79        let id1 = TraceId::new();
80        let id2 = TraceId::new();
81        assert_ne!(id1, id2);
82    }
83
84    #[test]
85    fn it_should_serialize_trace_id_to_json() {
86        let trace_id = TraceId::new();
87        let json = serde_json::to_string(&trace_id).unwrap();
88        assert!(json.contains('-')); // UUIDs contain hyphens
89    }
90
91    #[test]
92    fn it_should_deserialize_trace_id_from_json() {
93        let uuid = Uuid::new_v4();
94        let json = format!("\"{uuid}\"");
95        let trace_id: TraceId = serde_json::from_str(&json).unwrap();
96        assert_eq!(trace_id.inner(), &uuid);
97    }
98
99    #[test]
100    fn it_should_display_trace_id_as_uuid_string() {
101        let uuid = Uuid::new_v4();
102        let trace_id = TraceId(uuid);
103        assert_eq!(trace_id.to_string(), uuid.to_string());
104    }
105
106    #[test]
107    fn it_should_provide_access_to_inner_uuid() {
108        let uuid = Uuid::new_v4();
109        let trace_id = TraceId(uuid);
110        assert_eq!(trace_id.inner(), &uuid);
111    }
112
113    #[test]
114    fn it_should_create_default_trace_id() {
115        let id1 = TraceId::default();
116        let id2 = TraceId::default();
117        assert_ne!(id1, id2); // Each default should be unique
118    }
119}