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
|
#![allow(dead_code)]
use chrono::{DateTime, Local};
use either::Either;
use flate2::read::GzDecoder;
#[cfg(feature = "compress")]
use std::ffi::OsStr;
use std::{
fs::File,
io::{BufRead, BufReader},
ops::Add,
path::{Path, PathBuf},
};
const CTRL_INDEX: &str = "CTRL_INDEX";
pub fn file(filename: &str) -> PathBuf {
let mut f = dir();
f.push(filename);
f
}
const TS: &str = "%Y-%m-%d_%H-%M-%S";
pub fn dir() -> PathBuf {
let mut d = PathBuf::new();
d.push("log_files");
add_prog_name(&mut d);
d.push(now_local().format(TS).to_string());
d
}
fn add_prog_name(pb: &mut PathBuf) {
let path = PathBuf::from(std::env::args().next().unwrap());
let filename = path.file_stem().unwrap(/*ok*/).to_string_lossy();
let (progname, _) = filename.rsplit_once('-').unwrap_or((&filename, ""));
pb.push(progname);
}
// launch child processes from same executable and set for each of them an environment variable
// with a specific number, and then return None,
// or, in child processes, find this environment variable and return its value
pub fn dispatch(count: u8) -> Option<u8> {
match std::env::var(CTRL_INDEX) {
Err(_) => {
println!("dispatcher");
let progname = std::env::args().next().unwrap();
let nocapture = std::env::args().any(|a| a == "--nocapture");
for value in 0..count {
let mut command = std::process::Command::new(progname.clone());
if nocapture {
command.arg("--nocapture");
}
let status = command
.env(CTRL_INDEX, value.to_string())
.status()
.expect("Command failed to start");
assert!(status.success());
}
None
}
Ok(value) => {
println!("executor {value}");
Some(value.parse().unwrap())
}
}
}
#[must_use]
pub fn now_local() -> DateTime<Local> {
Local::now()
}
pub struct Stopwatch(DateTime<Local>);
impl Default for Stopwatch {
fn default() -> Self {
Stopwatch(now_local())
}
}
impl Drop for Stopwatch {
fn drop(&mut self) {
log::info!(
"Task executed in {} ms.",
(now_local() - self.0).num_milliseconds()
);
}
}
pub fn wait_for_start_of_second() {
loop {
let ms = Local::now().timestamp_subsec_millis();
if ms < 50 {
break;
} else {
std::thread::sleep(std::time::Duration::from_millis((1010_u32 - ms).into()));
}
}
}
pub fn wait_for_end_of_second() {
loop {
let ms = Local::now().timestamp_subsec_millis();
if ms > 980 {
break;
} else {
std::thread::sleep(std::time::Duration::from_millis((990_u32 - ms).into()));
}
}
}
// Count all log lines written in all files in the given folder
// ".gz" files are decompressed first
pub fn count_log_lines(directory: &Path) -> usize {
// read all files
let pattern = directory.display().to_string().add("/*");
let all_files = match glob::glob(&pattern) {
Err(e) => panic!("Is this ({pattern}) really a directory? Listing failed with {e}",),
Ok(globresults) => globresults,
};
let mut total_line_count = 0_usize;
for file in all_files.into_iter() {
let pathbuf = file.unwrap_or_else(|e| panic!("Ups - error occured: {e}"));
let mut reader: Either<BufReader<GzDecoder<File>>, BufReader<File>> =
match pathbuf.extension() {
#[cfg(feature = "compress")]
Some(os_str) if os_str == AsRef::<OsStr>::as_ref("gz") => {
// unpack
Either::Left(BufReader::new(GzDecoder::new(
File::open(&pathbuf)
.unwrap_or_else(|e| panic!("Cannot open file {pathbuf:?} due to {e}")),
)))
}
_ => {
Either::Right(BufReader::new(File::open(&pathbuf).unwrap_or_else(|e| {
panic!("Cannot open file {pathbuf:?} due to {e}")
})))
}
};
let mut buffer = String::new();
let mut line_count = 0_usize;
while reader.read_line(&mut buffer).unwrap() > 0 {
line_count += 1;
}
total_line_count += line_count;
}
total_line_count
}
|