1use file_rotate::{
10 compression::Compression,
11 suffix::{AppendTimestamp, FileLimit},
12 ContentLimit, FileRotate,
13};
14use std::{
15 env,
16 ffi::OsStr,
17 fmt::Debug,
18 io,
19 io::Write,
20 path::{Path, PathBuf},
21};
22use tracing_appender::non_blocking::{NonBlocking, WorkerGuard};
23
24pub(super) fn file_rotater(
35 dir: &PathBuf,
36 max_bytes: usize,
37 uncompressed_files: usize,
38 max_files: usize,
39) -> (NonBlocking, WorkerGuard) {
40 let binary_name = env::current_exe()
41 .map(|path| {
42 path.file_stem()
43 .unwrap_or(OsStr::new("safe"))
44 .to_string_lossy()
45 .into_owned()
46 })
47 .unwrap_or_else(|_| "safe".to_string());
48
49 let file_appender = FileRotateAppender::make_rotate_appender(
50 dir,
51 format!("{binary_name}.log"),
52 AppendTimestamp::default(FileLimit::MaxFiles(max_files)),
53 ContentLimit::BytesSurpassed(max_bytes),
54 Compression::OnRotate(uncompressed_files),
55 );
56
57 let non_blocking_builder = tracing_appender::non_blocking::NonBlockingBuilder::default();
59
60 non_blocking_builder
61 .lossy(false)
63 .finish(file_appender)
66}
67
68pub(super) struct FileRotateAppender {
77 writer: FileRotate<AppendTimestamp>,
78}
79
80impl FileRotateAppender {
81 pub(super) fn make_rotate_appender(
83 directory: impl AsRef<Path>,
84 file_name_prefix: impl AsRef<Path>,
85 file_limit: AppendTimestamp,
86 max_log_size: ContentLimit,
87 compression: Compression,
88 ) -> Self {
89 let log_directory = directory.as_ref();
90 let log_filename_prefix = file_name_prefix.as_ref();
91 let path = Path::new(&log_directory).join(log_filename_prefix);
92 let writer = FileRotate::new(
93 Path::new(&path),
94 file_limit,
95 max_log_size,
96 compression,
97 #[cfg(unix)]
98 None,
99 );
100
101 Self { writer }
102 }
103}
104
105impl Write for FileRotateAppender {
106 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
107 self.writer.write(buf)
108 }
109
110 fn flush(&mut self) -> io::Result<()> {
111 self.writer.flush()
112 }
113}
114
115use std::fmt;
116
117impl Debug for FileRotateAppender {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 f.debug_struct("FileRotateAppender").finish()
120 }
121}