1use std::sync::{Arc, Mutex, OnceLock};
21use std::time::{Instant, SystemTime, UNIX_EPOCH};
22
23#[derive(Clone)]
25pub enum Sink {
26 Stderr,
28 Memory(Arc<Mutex<Vec<String>>>),
30}
31
32static START: OnceLock<Instant> = OnceLock::new();
33
34pub fn line(holder: Option<&str>, ev: &str, fields: serde_json::Value) -> String {
37 let ts_ms = SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_millis() as u64).unwrap_or(0);
38 let mono_ms = START.get_or_init(Instant::now).elapsed().as_millis() as u64;
39 let head = format!(
40 "{{\"ts_ms\":{ts_ms},\"mono_ms\":{mono_ms},\"holder\":{},\"ev\":{}",
41 serde_json::to_string(&holder).unwrap_or_else(|_| "null".into()),
42 serde_json::to_string(ev).unwrap_or_else(|_| "\"?\"".into()),
43 );
44 let rest = match fields {
45 serde_json::Value::Object(m) if !m.is_empty() => {
46 let body = serde_json::to_string(&serde_json::Value::Object(m)).unwrap_or_default();
47 format!(",{}", &body[1..body.len() - 1])
48 }
49 _ => String::new(),
50 };
51 format!("{head}{rest}}}")
52}
53
54impl super::Syncer {
55 pub fn trace(&self, ev: &str, fields: serde_json::Value) {
57 let Some(sink) = &self.cfg.event_trace else { return };
58 let holder = self
59 .lease
60 .as_ref()
61 .map(|l| l.holder_id.clone())
62 .or_else(|| super::lease::incarnation(self).ok().map(|i| i.holder_id));
63 let l = line(holder.as_deref(), ev, fields);
64 match sink {
65 Sink::Stderr => eprintln!("{l}"),
66 Sink::Memory(buf) => buf.lock().unwrap().push(l),
67 }
68 }
69
70 pub fn trace_requests(&self) -> serde_json::Value {
72 match self.store.request_counts() {
73 Some(c) => serde_json::to_value(c).unwrap_or(serde_json::Value::Null),
74 None => serde_json::Value::Null,
75 }
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 #[test]
82 fn a_line_starts_with_the_pinned_prefix_and_parses() {
83 let l = super::line(Some("h1"), "gc", serde_json::json!({"path": "a/b", "result": "deleted", "z": 1}));
84 assert!(l.starts_with("{\"ts_ms\":"), "{l}");
85 let v: serde_json::Value = serde_json::from_str(&l).expect("a trace line is JSON");
86 assert_eq!(v["holder"], "h1");
87 assert_eq!(v["ev"], "gc");
88 assert_eq!(v["path"], "a/b");
89 assert!(v["mono_ms"].is_u64());
90 let empty = super::line(None, "barrier_start", serde_json::json!({}));
91 let v: serde_json::Value = serde_json::from_str(&empty).expect("no fields still parses");
92 assert!(v["holder"].is_null());
93 }
94}