1use std::{io, time::Duration};
2
3use crate::{Level, QueueFullCallback, QueueFullPolicy, logger, output::RotationConfig};
4
5pub struct FlashLogGuard {
8 _private: (),
9}
10
11impl Drop for FlashLogGuard {
12 fn drop(&mut self) {
13 let _ = logger::stop_polling_thread();
14 let _ = logger::poll(true);
15 }
16}
17
18pub struct FlashLogBuilder {
36 level: Level,
37 flush_delay: Duration,
38 flush_buffer_size: u32,
39 flush_level: Level,
40 queue_full_policy: QueueFullPolicy,
41 queue_full_callback: Option<QueueFullCallback>,
42 log_file: Option<String>,
43 rotation: Option<RotationConfig>,
44 header_pattern: Option<String>,
45 poller_interval: Duration,
46 poller_core_affinity: Option<usize>,
47}
48
49impl Default for FlashLogBuilder {
50 fn default() -> Self {
51 Self::new()
52 }
53}
54
55impl FlashLogBuilder {
56 pub fn new() -> Self {
58 Self {
59 level: Level::DBG,
60 flush_delay: Duration::from_secs(3),
61 flush_buffer_size: 8 * 1024,
62 flush_level: Level::OFF,
63 queue_full_policy: QueueFullPolicy::Drop,
64 queue_full_callback: None,
65 log_file: None,
66 rotation: None,
67 header_pattern: None,
68 poller_interval: Duration::from_millis(1),
69 poller_core_affinity: None,
70 }
71 }
72
73 pub fn level(mut self, level: Level) -> Self {
75 self.level = level;
76 self
77 }
78
79 pub fn flush_delay(mut self, delay: Duration) -> Self {
81 self.flush_delay = delay;
82 self
83 }
84
85 pub fn flush_buffer_size(mut self, bytes: u32) -> Self {
87 self.flush_buffer_size = bytes;
88 self
89 }
90
91 pub fn flush_on(mut self, level: Level) -> Self {
93 self.flush_level = level;
94 self
95 }
96
97 pub fn queue_full_policy(mut self, policy: QueueFullPolicy) -> Self {
99 self.queue_full_policy = policy;
100 self
101 }
102
103 pub fn queue_full_callback(mut self, callback: QueueFullCallback) -> Self {
105 self.queue_full_callback = Some(callback);
106 self
107 }
108
109 pub fn log_file(mut self, path: impl Into<String>) -> Self {
111 self.log_file = Some(path.into());
112 self
113 }
114
115 pub fn rotation(mut self, config: RotationConfig) -> Self {
117 self.rotation = Some(config);
118 self
119 }
120
121 pub fn header_pattern(mut self, pattern: impl Into<String>) -> Self {
123 self.header_pattern = Some(pattern.into());
124 self
125 }
126
127 pub fn poller_interval(mut self, interval: Duration) -> Self {
129 self.poller_interval = interval;
130 self
131 }
132
133 pub fn poller_core_affinity(mut self, core_id: usize) -> Self {
136 self.poller_core_affinity = Some(core_id);
137 self
138 }
139
140 pub fn start(self) -> io::Result<FlashLogGuard> {
145 crate::thread_buffer::preallocate();
147
148 logger::set_level(self.level);
149 logger::set_flush_delay(self.flush_delay.as_nanos() as i64);
150 logger::set_flush_buffer_size(self.flush_buffer_size);
151 logger::flush_on(self.flush_level);
152 logger::set_queue_full_policy(self.queue_full_policy);
153 logger::set_queue_full_callback(self.queue_full_callback);
154
155 if let Some(pattern) = &self.header_pattern {
156 logger::set_header_pattern(pattern)?;
157 }
158
159 if let Some(path) = &self.log_file {
160 if let Some(rotation) = self.rotation {
161 logger::set_log_file_with_rotation(path, rotation)?;
162 } else {
163 logger::set_log_file(path)?;
164 }
165 }
166
167 let interval_ns = self.poller_interval.as_nanos() as i64;
168 if let Some(core_id) = self.poller_core_affinity {
169 logger::start_polling_thread_on_core(interval_ns, core_id)?;
170 } else {
171 logger::start_polling_thread(interval_ns)?;
172 }
173
174 Ok(FlashLogGuard { _private: () })
175 }
176}
177
178pub fn builder() -> FlashLogBuilder {
180 FlashLogBuilder::new()
181}