doric/backend/
material.rs

1use 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}