Skip to main content

dig_logging/
correlation.rs

1//! Correlation ids (SPEC §6).
2//!
3//! - `run_id` — a UUIDv4 minted once at [`init`](crate::init), stamped on every record, so one
4//!   process run is groupable across rotated files and restarts are distinguishable.
5//! - `op_id` — a span field a consumer attaches to a top-level operation; it flattens onto every
6//!   event inside the span (handled by the JSON layer), so it is a convention, not code here.
7//! - `parent_op_id` — read once from the `DIG_OP_ID` env var, tying this run to the operation in the
8//!   parent process that spawned it (installer → service; updater broker → worker).
9
10use uuid::Uuid;
11
12/// The reserved span-field name a consumer uses to tag a top-level operation (SPEC §6).
13pub const OP_ID_FIELD: &str = "op_id";
14
15/// The env var a parent process sets in a child's environment to propagate its operation id.
16pub const ENV_DIG_OP_ID: &str = "DIG_OP_ID";
17
18/// Mint a fresh run id for this process run.
19pub fn new_run_id() -> String {
20    Uuid::new_v4().to_string()
21}
22
23/// Read the propagated parent operation id from an injected env-getter: the `DIG_OP_ID` value when
24/// present + non-blank, else `None`. Pure, so the pickup is testable without the process environment.
25pub fn parent_op_id<G: Fn(&str) -> Option<String>>(get: G) -> Option<String> {
26    get(ENV_DIG_OP_ID)
27        .map(|value| value.trim().to_string())
28        .filter(|value| !value.is_empty())
29}
30
31/// Read the parent operation id from the real environment. See [`parent_op_id`].
32pub fn parent_op_id_from_env() -> Option<String> {
33    parent_op_id(|key| std::env::var(key).ok())
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39
40    #[test]
41    fn run_ids_are_unique_uuids() {
42        let a = new_run_id();
43        let b = new_run_id();
44        assert_ne!(a, b);
45        assert!(Uuid::parse_str(&a).is_ok());
46    }
47
48    #[test]
49    fn parent_op_id_reads_non_blank_env() {
50        let get = |key: &str| (key == ENV_DIG_OP_ID).then(|| "op-abc123".to_string());
51        assert_eq!(parent_op_id(get), Some("op-abc123".to_string()));
52    }
53
54    #[test]
55    fn parent_op_id_absent_or_blank_is_none() {
56        assert_eq!(parent_op_id(|_| None), None);
57        assert_eq!(parent_op_id(|_| Some("   ".to_string())), None);
58    }
59}