doric/backend/
material.rs1use std::fs;
2use std::fs::OpenOptions;
3use std::io::prelude::*;
4use std::path::Path;
5
6use super::LoggerConfig;
7use crate::encode::parser::Message;
8use crate::runtime::append::Appender;
9
10#[derive(Debug)]
11pub struct Material {
12 pub lc: LoggerConfig,
13}
14
15fn seg_size(dst: &String) -> u64 {
16 let exist = Path::new(dst.as_str()).exists();
17 if !exist {
18 return 0;
19 }
20
21 let x = fs::metadata(dst.as_str()).unwrap().len();
22 x
23}
24
25fn seg_rename(src: &String, dst: &String) -> std::io::Result<()> {
26 let exist = Path::new(src.as_str()).exists();
27 if !exist {
28 return Ok(());
29 }
30
31 fs::rename(src.as_str(), dst.as_str())
32}
33
34fn seg_remove(dst: &String) -> std::io::Result<()> {
35 let exist = Path::new(dst.as_str()).exists();
36 if !exist {
37 return Ok(());
38 }
39
40 fs::remove_file(dst.as_str())
41}
42
43fn segs_count(file_path: &String) -> Vec<String> {
44 let path = Path::new(file_path.as_str());
45 let parent = path.parent();
46 let log_dir = parent.unwrap().display().to_string();
47
48 let paths = fs::read_dir(log_dir.as_str()).unwrap();
49 let l = file_path.len();
50 let pattern = file_path.as_str();
51
52 let mut segs: Vec<String> = vec![];
53 for entry in paths {
54 let entry = entry.unwrap();
55 let path = entry.path();
56 if !path.is_dir() {
57 let s = path.display().to_string();
58 let d = s.get(..l);
59 match d {
60 None => {}
61 Some(d) => match pattern.find(d) {
62 None => {}
63 Some(_v) => {
64 segs.push(s);
65 }
66 },
67 }
68 }
69 }
70
71 segs
72}
73
74fn segs_rotate(dst: &String, segs: &mut Vec<String>, count: usize, rename: bool) {
75 let tot_len = segs.len();
76 if tot_len == 0 {
77 return;
78 }
79
80 segs.reverse();
81 let del_len = tot_len - count;
82
83 if del_len > 0 {
84 for i in 0..del_len {
85 match seg_remove(&segs[i]) {
86 Ok(_v) => {}
87 Err(e) => {
88 println!("segs_rotate_slow remove failed {:?}", e);
89 }
90 }
91 }
92 }
93
94 if rename {
95 for i in del_len..tot_len {
96 let new_name = format!("{}.{}", dst, tot_len - i);
97 match seg_rename(&segs[i].to_string(), &new_name) {
98 Ok(_v) => {}
99 Err(e) => {
100 println!("segs_rotate_slow rename failed {:?}", e);
101 }
102 }
103 }
104 }
105}
106
107impl Material {
108 pub fn new(conf: LoggerConfig) -> Material {
109 Material { lc: conf }
110 }
111
112 fn rotate(&self, current_len: usize) -> std::io::Result<()> {
113 let mut tot: usize = 0;
114 let exist = Path::new(self.lc.path.as_str()).exists();
115 if exist {
116 let seg_sz = seg_size(&self.lc.path);
117 tot += seg_sz as usize + current_len;
118 }
119
120 let mut segs = segs_count(&self.lc.path);
121 let seg_count = segs.len();
122
123 if tot <= self.lc.max_size as usize && seg_count < self.lc.max_segments {
124 return Ok(());
125 }
126
127 if tot > self.lc.max_size as usize {
128 segs_rotate(&self.lc.path, &mut segs, self.lc.max_segments - 1, true);
129 } else {
130 if exist {
131 segs_rotate(&self.lc.path, &mut segs, self.lc.max_segments, false);
132 } else {
133 segs_rotate(&self.lc.path, &mut segs, self.lc.max_segments - 1, false);
134 }
135 }
136
137 Ok(())
138 }
139
140 fn output(&self, msg: &Message) {
141 let data = format!(
142 "{} {} {}\n",
143 chrono::offset::Local::now().to_string(),
144 msg.level.to_string(),
145 msg.args
146 );
147
148 match self.rotate(data.len()) {
149 Ok(_v) => {}
150 Err(e) => {
151 println!("rotate failed {:?}", e);
152 }
153 }
154
155 let mut file = OpenOptions::new()
156 .create(true)
157 .append(true)
158 .open(self.lc.path.as_str())
159 .unwrap();
160 file.write(data.as_bytes()).unwrap();
161 }
162}
163
164impl Appender for Material {
165 fn append(&self, msg: &Message) -> Result<(), String> {
166 self.output(msg);
167 Ok(())
168 }
169}