flexi_logger/writers/file_log_writer/
builder.rs1use crate::flexi_error::FlexiLoggerError;
2use crate::formats::default_format;
3use crate::{Cleanup, Criterion, FileSpec, FormatFunction, Naming, WriteMode};
4use std::path::{Path, PathBuf};
5use std::sync::Arc;
6
7use super::{FileLogWriter, FileLogWriterConfig, LogWriter, RotationConfig, State};
8
9#[allow(clippy::struct_excessive_bools, clippy::module_name_repetitions)]
11pub struct FileLogWriterBuilder {
12 cfg_print_message: bool,
13 cfg_append: bool,
14 cfg_write_mode: WriteMode,
15 file_spec: FileSpec,
16 cfg_o_create_symlink: Option<PathBuf>,
17 cfg_line_ending: &'static [u8],
18 format: FormatFunction,
19 o_rotation_config: Option<RotationConfig>,
20 max_log_level: log::LevelFilter,
21 cleanup_in_background_thread: bool,
22 use_utc: bool,
23}
24
25impl FileLogWriterBuilder {
27 pub(crate) fn new(file_spec: FileSpec) -> Self {
28 Self {
29 o_rotation_config: None,
30 cfg_print_message: false,
31 file_spec,
32 cfg_append: false,
33 cfg_write_mode: WriteMode::Direct,
34 cfg_o_create_symlink: None,
35 cfg_line_ending: super::UNIX_LINE_ENDING,
36 format: default_format,
37 max_log_level: log::LevelFilter::Trace,
38 cleanup_in_background_thread: true,
39 use_utc: false,
40 }
41 }
42
43 #[must_use]
46 pub fn print_message(mut self) -> Self {
47 self.cfg_print_message = true;
48 self
49 }
50
51 #[must_use]
54 pub fn format(mut self, format: FormatFunction) -> Self {
55 self.format = format;
56 self
57 }
58
59 #[must_use]
74 pub fn cleanup_in_background_thread(mut self, use_background_thread: bool) -> Self {
75 self.cleanup_in_background_thread = use_background_thread;
76 self
77 }
78
79 #[must_use]
108 pub fn rotate(mut self, criterion: Criterion, naming: Naming, cleanup: Cleanup) -> Self {
109 self.o_rotation_config = Some(RotationConfig {
110 criterion,
111 naming,
112 cleanup,
113 });
114 self.file_spec.if_default_use_timestamp(false);
115 self
116 }
117
118 #[must_use]
120 pub(crate) fn file_spec(mut self, mut file_spec: FileSpec) -> Self {
121 if self.o_rotation_config.is_some() {
122 file_spec.if_default_use_timestamp(false);
123 }
124 self.file_spec = file_spec;
125 self
126 }
127
128 #[must_use]
131 pub fn append(mut self) -> Self {
132 self.cfg_append = true;
133 self
134 }
135
136 #[must_use]
140 pub fn max_level(mut self, max_log_level: log::LevelFilter) -> Self {
141 self.max_log_level = max_log_level;
142 self
143 }
144
145 #[must_use]
147 pub fn use_utc(mut self) -> Self {
148 self.file_spec.use_utc = true;
149 self.use_utc = true;
150 self
151 }
152
153 #[must_use]
156 pub fn create_symlink<P: Into<PathBuf>>(mut self, symlink: P) -> Self {
157 self.cfg_o_create_symlink = Some(symlink.into());
158 self
159 }
160
161 #[must_use]
163 pub fn use_windows_line_ending(mut self) -> Self {
164 self.cfg_line_ending = super::WINDOWS_LINE_ENDING;
165 self
166 }
167
168 #[must_use]
172 pub fn write_mode(mut self, write_mode: WriteMode) -> Self {
173 self.cfg_write_mode = write_mode;
174 self
175 }
176
177 pub(crate) fn assert_write_mode(&self, write_mode: WriteMode) -> Result<(), FlexiLoggerError> {
178 if self.cfg_write_mode == write_mode {
179 Ok(())
180 } else {
181 Err(FlexiLoggerError::Reset)
182 }
183 }
184
185 #[must_use]
186 pub(crate) fn get_write_mode(&self) -> &WriteMode {
187 &self.cfg_write_mode
188 }
189
190 pub fn try_build(self) -> Result<FileLogWriter, FlexiLoggerError> {
196 Ok(FileLogWriter::new(
197 self.try_build_state()?,
198 self.max_log_level,
199 self.format,
200 ))
201 }
202
203 pub fn try_build_with_handle(
212 self,
213 ) -> Result<(ArcFileLogWriter, FileLogWriterHandle), FlexiLoggerError> {
214 Ok(ArcFileLogWriter::new_with_handle(FileLogWriter::new(
215 self.try_build_state()?,
216 self.max_log_level,
217 self.format,
218 )))
219 }
220
221 pub(super) fn try_build_state(&self) -> Result<State, FlexiLoggerError> {
222 let dir = self.file_spec.get_directory();
224 let p_directory = Path::new(&dir);
225 std::fs::create_dir_all(p_directory)?;
226 if !std::fs::metadata(p_directory)?.is_dir() {
227 return Err(FlexiLoggerError::OutputBadDirectory);
228 };
229
230 #[cfg(feature = "async")]
231 let cleanup_in_background_thread = if let WriteMode::AsyncWith {
232 pool_capa: _,
233 message_capa: _,
234 flush_interval: _,
235 } = self.cfg_write_mode
236 {
237 false
238 } else {
239 self.cleanup_in_background_thread
240 };
241 #[cfg(not(feature = "async"))]
242 let cleanup_in_background_thread = self.cleanup_in_background_thread;
243
244 Ok(State::new(
245 FileLogWriterConfig {
246 print_message: self.cfg_print_message,
247 append: self.cfg_append,
248 line_ending: self.cfg_line_ending,
249 write_mode: self.cfg_write_mode,
250 file_spec: self.file_spec.clone(),
251 o_create_symlink: self.cfg_o_create_symlink.clone(),
252 use_utc: self.use_utc,
253 },
254 self.o_rotation_config.clone(),
255 cleanup_in_background_thread,
256 ))
257 }
258}
259
260impl FileLogWriterBuilder {
264 #[must_use]
267 pub fn o_print_message(mut self, print_message: bool) -> Self {
268 self.cfg_print_message = print_message;
269 self
270 }
271
272 #[must_use]
283 pub fn o_rotate(mut self, rotate_config: Option<(Criterion, Naming, Cleanup)>) -> Self {
284 if let Some((criterion, naming, cleanup)) = rotate_config {
285 self.o_rotation_config = Some(RotationConfig {
286 criterion,
287 naming,
288 cleanup,
289 });
290 self.file_spec.if_default_use_timestamp(false);
291 } else {
292 self.o_rotation_config = None;
293 self.file_spec.if_default_use_timestamp(true);
294 }
295 self
296 }
297
298 #[must_use]
301 pub fn o_append(mut self, append: bool) -> Self {
302 self.cfg_append = append;
303 self
304 }
305
306 #[must_use]
309 pub fn o_create_symlink<S: Into<PathBuf>>(mut self, symlink: Option<S>) -> Self {
310 self.cfg_o_create_symlink = symlink.map(Into::into);
311 self
312 }
313}
314
315pub struct ArcFileLogWriter(Arc<FileLogWriter>);
317impl ArcFileLogWriter {
318 pub(crate) fn new_with_handle(flw: FileLogWriter) -> (Self, FileLogWriterHandle) {
319 let a_flw = Arc::new(flw);
320 (Self(Arc::clone(&a_flw)), FileLogWriterHandle(a_flw))
321 }
322}
323impl std::ops::Deref for ArcFileLogWriter {
324 type Target = FileLogWriter;
325 fn deref(&self) -> &FileLogWriter {
326 &(self.0)
327 }
328}
329impl Clone for ArcFileLogWriter {
330 fn clone(&self) -> Self {
331 Self(Arc::clone(&self.0))
332 }
333}
334impl std::io::Write for ArcFileLogWriter {
335 fn write(&mut self, buffer: &[u8]) -> std::result::Result<usize, std::io::Error> {
336 (*self.0).plain_write(buffer)
337 }
338 fn flush(&mut self) -> std::result::Result<(), std::io::Error> {
339 LogWriter::flush(&*self.0)
340 }
341}
342
343pub struct FileLogWriterHandle(Arc<FileLogWriter>);
346impl Drop for FileLogWriterHandle {
347 fn drop(&mut self) {
348 self.0.shutdown();
349 }
350}