rivet_logger/processors/
uid.rs1use std::io;
2use std::sync::Mutex;
3
4use getrandom::getrandom;
5
6use crate::logger::{BoxError, LogRecord, LogValue, LoggerError, Processor};
7
8pub struct Uid {
9 uid: Mutex<String>,
10}
11
12impl Uid {
13 pub fn new(length: usize) -> Result<Self, LoggerError> {
14 if !(1..=32).contains(&length) {
15 return Err(LoggerError::InvalidProcessorConfig(
16 "The uid length must be an integer between 1 and 32".to_string(),
17 ));
18 }
19
20 Ok(Self {
21 uid: Mutex::new(generate_uid(length)?),
22 })
23 }
24
25 pub fn get_uid(&self) -> String {
26 match self.uid.lock() {
27 Ok(uid) => uid.clone(),
28 Err(poisoned) => poisoned.into_inner().clone(),
29 }
30 }
31}
32
33impl Default for Uid {
34 fn default() -> Self {
35 Self::new(7).expect("default uid length must be valid")
37 }
38}
39
40impl Processor for Uid {
41 fn process(&self, mut record: LogRecord) -> Result<LogRecord, BoxError> {
42 record
43 .extra
44 .insert("uid".to_string(), LogValue::String(self.get_uid()));
45 Ok(record)
46 }
47
48 fn reset(&self) -> Result<(), BoxError> {
49 let mut uid = self
50 .uid
51 .lock()
52 .map_err(|_| Box::new(io::Error::other("uid lock poisoned")) as BoxError)?;
53 let length = uid.len();
54 *uid = generate_uid(length)
55 .map_err(|err| Box::new(io::Error::other(err.to_string())) as BoxError)?;
56 Ok(())
57 }
58}
59
60fn generate_uid(length: usize) -> Result<String, LoggerError> {
61 let mut bytes = vec![0_u8; length.div_ceil(2)];
62 getrandom(&mut bytes).map_err(|err| LoggerError::InvalidProcessorConfig(err.to_string()))?;
63
64 let mut hex = String::with_capacity(bytes.len() * 2);
65 for byte in bytes {
66 let _ = std::fmt::Write::write_fmt(&mut hex, format_args!("{byte:02x}"));
67 }
68 hex.truncate(length);
69
70 Ok(hex)
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn validates_uid_length() {
79 assert!(Uid::new(0).is_err());
80 assert!(Uid::new(33).is_err());
81 assert!(Uid::new(7).is_ok());
82 }
83
84 #[test]
85 fn reset_regenerates_uid() {
86 let processor = Uid::new(8).expect("uid processor should initialize");
87 let first = processor.get_uid();
88 processor.reset().expect("reset should succeed");
89 let second = processor.get_uid();
90
91 assert_eq!(first.len(), 8);
92 assert_eq!(second.len(), 8);
93 assert_ne!(first, second);
94 }
95}