bitwarden_logging/
global.rs1use std::sync::{Arc, OnceLock};
4
5use crate::{CircularBuffer, FlightRecorderConfig, FlightRecorderEvent, FlightRecorderLayer};
6
7static FLIGHT_RECORDER_BUFFER: OnceLock<Arc<CircularBuffer<FlightRecorderEvent>>> = OnceLock::new();
9
10static FLIGHT_RECORDER_LEVEL: OnceLock<tracing::Level> = OnceLock::new();
14
15#[must_use]
25pub fn init_flight_recorder(config: FlightRecorderConfig) -> FlightRecorderLayer {
26 let _ = FLIGHT_RECORDER_LEVEL.set(config.level);
27 let layer = FlightRecorderLayer::new(config);
28 let _ = FLIGHT_RECORDER_BUFFER.set(layer.buffer());
29 layer
30}
31
32pub fn write_flight_recorder(event: FlightRecorderEvent, level: tracing::Level) {
40 if let Some(floor) = FLIGHT_RECORDER_LEVEL.get()
42 && level > *floor
43 {
44 return;
45 }
46 if let Some(buffer) = get_flight_recorder_buffer() {
47 buffer.push(event);
48 }
49}
50
51pub fn get_flight_recorder_buffer() -> Option<Arc<CircularBuffer<FlightRecorderEvent>>> {
55 FLIGHT_RECORDER_BUFFER.get().cloned()
56}
57
58#[must_use]
62pub fn read_flight_recorder() -> Vec<FlightRecorderEvent> {
63 get_flight_recorder_buffer()
64 .map(|buffer| buffer.read())
65 .unwrap_or_default()
66}
67
68#[must_use]
72pub fn flight_recorder_count() -> usize {
73 get_flight_recorder_buffer()
74 .map(|buffer| buffer.len())
75 .unwrap_or(0)
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn test_config_default_values() {
84 let config = FlightRecorderConfig::default();
85 assert_eq!(config.buffer_size.get(), 1000);
86 assert_eq!(config.level, tracing::Level::DEBUG);
87 }
88
89 #[test]
90 fn test_read_before_init_returns_empty() {
91 let events = read_flight_recorder();
95 let _ = events;
97 }
98
99 fn event(marker: &str, level: &str) -> FlightRecorderEvent {
100 FlightRecorderEvent {
101 timestamp: 0,
102 level: level.to_string(),
103 target: "test::module".to_string(),
104 message: marker.to_string(),
105 fields: std::collections::HashMap::new(),
106 }
107 }
108
109 #[test]
110 fn test_write_flight_recorder_respects_level_floor() {
111 let config = FlightRecorderConfig::new(
114 std::num::NonZeroUsize::new(100).expect("non-zero"),
115 tracing::Level::INFO,
116 );
117 let _ = init_flight_recorder(config);
118
119 write_flight_recorder(event("fr-drop-debug", "DEBUG"), tracing::Level::DEBUG);
121 write_flight_recorder(event("fr-keep-info", "INFO"), tracing::Level::INFO);
123 write_flight_recorder(event("fr-keep-error", "ERROR"), tracing::Level::ERROR);
124
125 let messages: Vec<String> = read_flight_recorder()
126 .into_iter()
127 .map(|e| e.message)
128 .collect();
129 assert!(messages.contains(&"fr-keep-info".to_string()));
130 assert!(messages.contains(&"fr-keep-error".to_string()));
131 assert!(!messages.contains(&"fr-drop-debug".to_string()));
132 }
133}