-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathmod.rs
149 lines (132 loc) · 4.83 KB
/
mod.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
mod aggregator;
mod reader;
mod searcher;
mod writer;
pub use aggregator::*;
// `reader` is utilized in `searcher` for metric deserialization.
pub use reader::*;
// Currently searcher haven't been utilized. But it intends to provide search ability for metric with index files generated in `writer`.
pub use searcher::*;
pub use writer::*;
use crate::{base::MetricItem, Result};
use lazy_static::lazy_static;
use regex::Regex;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};
// METRIC_FILENAME_SUFFIX represents the suffix of the metric file.
static METRIC_FILENAME_SUFFIX: &str = "metrics.log";
// METRIC_IDX_SUFFIX represents the suffix of the metric index file.
static METRIC_IDX_SUFFIX: &str = ".idx";
// FILE_LOCK_SUFFIX represents the suffix of the lock file.
static FILE_LOCK_SUFFIX: &str = ".lck";
// FILE_PID_PREFIX represents the pid flag of filename.
static FILE_PID_PREFIX: &str = "pid";
static METRIC_FILE_PATTERN: &str = r"\.[0-9]{4}-[0-9]{2}-[0-9]{2}(\.[0-9]*)?";
type MetricItemVec = Vec<MetricItem>;
type MetricTimeMap = HashMap<u64, MetricItemVec>;
lazy_static! {
static ref METRIC_FILE_REGEX: Regex = Regex::new(METRIC_FILE_PATTERN).unwrap();
}
// MetricLogWriter writes and flushes metric items to current metric log.
pub trait MetricLogWriter {
fn write(&mut self, ts: u64, items: &mut Vec<MetricItem>) -> Result<()>;
}
// MetricSearcher searches metric items from the metric log file under given condition.
pub trait MetricSearcher {
fn find_by_time_and_resource(
&self,
begin_time_ms: u64,
end_time_ms: u64,
resource: &str,
) -> Result<MetricItemVec>;
fn find_from_time_with_max_lines(
&self,
begin_time_ms: u64,
max_lines: usize,
) -> Result<MetricItemVec>;
}
// Generate the metric file name from the service name.
fn form_metric_filename(service_name: &str, with_pid: bool) -> String {
let dot = ".";
let separator = "-";
let mut filename = String::new();
if service_name.contains(dot) {
filename = service_name.replace(dot, separator);
}
let mut filename = format!("{}{}{}", filename, separator, METRIC_FILENAME_SUFFIX);
if with_pid {
let pid = std::process::id();
filename = format!("{}.pid{}", filename, pid);
}
filename
}
// Generate the metric index filename from the metric log filename.
fn form_metric_idx_filename(metric_filename: &str) -> String {
format!("{}{}", metric_filename, METRIC_IDX_SUFFIX)
}
fn filename_matches(filename: &str, base_filename: &str) -> bool {
if !filename.starts_with(base_filename) {
return false;
}
let part = &filename[base_filename.len()..];
// part is like: ".yyyy-MM-dd.number", eg. ".2018-12-24.11"
METRIC_FILE_REGEX.is_match(part)
}
fn list_metric_files_conditional(
base_dir: &PathBuf,
file_pattern: &Path,
predicate: fn(&str, &str) -> bool,
) -> Result<Vec<PathBuf>> {
let dir = fs::read_dir(base_dir)?;
let mut arr = Vec::new();
for f in dir {
let f = f?.path();
match f.file_name() {
Some(name) => {
if let Some(name) = name.to_str() {
if predicate(name, file_pattern.to_str().unwrap())
&& !name.ends_with(METRIC_IDX_SUFFIX)
&& !name.ends_with(FILE_LOCK_SUFFIX)
{
// Put the absolute path into the slice.
arr.push(Path::new(base_dir).join(name));
}
}
}
None => continue,
}
}
if arr.len() > 1 {
arr.sort_by(filename_comparator);
}
Ok(arr)
}
/// List metrics files according to `base_dir` (the directory of metrics files) and
/// `file_pattern` (metric file pattern).
fn list_metric_files(base_dir: &PathBuf, file_pattern: &Path) -> Result<Vec<PathBuf>> {
list_metric_files_conditional(base_dir, file_pattern, filename_matches)
}
/// Sort the metric files by their date time.
/// This function is used to remove the deprecated files, or create a new file in order.
#[allow(clippy::ptr_arg)]
fn filename_comparator(file1: &PathBuf, file2: &PathBuf) -> Ordering {
let name1 = file1.file_name().unwrap().to_str().unwrap();
let name2 = file2.file_name().unwrap().to_str().unwrap();
let a1 = name1.split('.').collect::<Vec<&str>>();
let a2 = name2.split('.').collect::<Vec<&str>>();
let mut date_str1 = a1[2];
let mut date_str2 = a2[2];
// in case of file name contains pid, skip it, like Sentinel-Admin-metrics.log.pid22568.2018-12-24
if a1[2].starts_with(FILE_PID_PREFIX) {
date_str1 = a1[3];
date_str2 = a2[3];
}
// compare date first
if date_str1 != date_str2 {
return date_str1.cmp(date_str2);
}
// same date, compare the file number
name1.cmp(name2)
}