Compare commits
2 Commits
v1.2.2
...
d7d32efb43
| Author | SHA1 | Date | |
|---|---|---|---|
| d7d32efb43 | |||
| fe82ef4b17 |
+41
-31
@@ -9,7 +9,6 @@ use tokio::{
|
|||||||
io::{self, AsyncBufReadExt, AsyncRead, AsyncWrite, AsyncWriteExt, BufReader, BufWriter},
|
io::{self, AsyncBufReadExt, AsyncRead, AsyncWrite, AsyncWriteExt, BufReader, BufWriter},
|
||||||
process,
|
process,
|
||||||
sync::mpsc,
|
sync::mpsc,
|
||||||
task::spawn_blocking,
|
|
||||||
time::{sleep, Duration},
|
time::{sleep, Duration},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -61,9 +60,9 @@ impl<'t> Logger<'t> {
|
|||||||
|
|
||||||
use std::io::ErrorKind as K;
|
use std::io::ErrorKind as K;
|
||||||
match tokio::fs::create_dir(&cg_path).await {
|
match tokio::fs::create_dir(&cg_path).await {
|
||||||
Ok(_) => log::debug!("created dir {}", cg_path.display()),
|
Ok(_) => debug!("created dir {}", cg_path.display()),
|
||||||
Err(e) if e.kind() == K::AlreadyExists => {
|
Err(e) if e.kind() == K::AlreadyExists => {
|
||||||
log::debug!("existing dir {}", cg_path.display())
|
debug!("existing dir {}", cg_path.display())
|
||||||
}
|
}
|
||||||
Err(e) => Err(e)?,
|
Err(e) => Err(e)?,
|
||||||
}
|
}
|
||||||
@@ -73,14 +72,14 @@ impl<'t> Logger<'t> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let control_file = &cg_path.join("cgroup.subtree_control");
|
let control_file = &cg_path.join("cgroup.subtree_control");
|
||||||
log::debug!("control file {}", control_file.display());
|
debug!("control file {}", control_file.display());
|
||||||
tokio::fs::write(control_file, b"+cpu +memory +pids +io").await?;
|
tokio::fs::write(control_file, b"+cpu +memory +pids +io").await?;
|
||||||
|
|
||||||
part = next_part;
|
part = next_part;
|
||||||
}
|
}
|
||||||
|
|
||||||
let procs_file = cg_path.join("cgroup.procs");
|
let procs_file = cg_path.join("cgroup.procs");
|
||||||
log::debug!("procs file {}", procs_file.display());
|
debug!("procs file {}", procs_file.display());
|
||||||
fs::write(&procs_file, b"0").await?;
|
fs::write(&procs_file, b"0").await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +92,7 @@ impl<'t> Logger<'t> {
|
|||||||
|
|
||||||
// forward signals
|
// forward signals
|
||||||
if let Some(child_pid) = child.id() {
|
if let Some(child_pid) = child.id() {
|
||||||
spawn_blocking(move || forward_signals_to(child_pid as i32)).await?;
|
forward_signals_to(child_pid as i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle output
|
// handle output
|
||||||
@@ -166,29 +165,28 @@ impl<'t> Logger<'t> {
|
|||||||
.open(log_file)
|
.open(log_file)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let link_src = &format!(
|
let link_src = &PathBuf::from(self.log_path)
|
||||||
"{path}/{name}.log",
|
.join(self.log_name)
|
||||||
path = self.log_path,
|
.with_added_extension("log");
|
||||||
name = self.log_name
|
let link_tgt = &self.archive_rel_path(ts);
|
||||||
);
|
|
||||||
let link_tgt = log_file
|
|
||||||
.strip_prefix(&format!("{}/", self.log_path))
|
|
||||||
.unwrap_or(log_file);
|
|
||||||
|
|
||||||
let _ = fs::remove_file(link_src).await;
|
let _ = fs::remove_file(link_src).await;
|
||||||
fs::symlink(link_tgt, link_src)
|
fs::symlink(link_tgt, link_src).await.map_err(|e| {
|
||||||
.await
|
format_err!(
|
||||||
.map_err(|e| format_err!("symlink {link_src} -> {link_tgt} failed: {e}",))?;
|
"symlink {s} -> {t} failed: {e}",
|
||||||
|
s = link_src.display(),
|
||||||
|
t = link_tgt.display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(file)
|
Ok(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn archive_path(&self, ts: Timestamp) -> String {
|
fn archive_path(&self, ts: Timestamp) -> PathBuf {
|
||||||
format!(
|
PathBuf::from(self.log_path).join(self.archive_rel_path(ts))
|
||||||
"{path}/archives/{file}",
|
}
|
||||||
path = self.log_path,
|
fn archive_rel_path(&self, ts: Timestamp) -> PathBuf {
|
||||||
file = self.archive_file(ts)
|
PathBuf::from("archives").join(self.archive_file(ts))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
fn archive_file(&self, ts: Timestamp) -> String {
|
fn archive_file(&self, ts: Timestamp) -> String {
|
||||||
format!(
|
format!(
|
||||||
@@ -206,7 +204,7 @@ fn forward_signals_to(pid: i32) {
|
|||||||
};
|
};
|
||||||
use signal_hook::{consts::*, low_level::register};
|
use signal_hook::{consts::*, low_level::register};
|
||||||
|
|
||||||
log::debug!("forwarding signals to pid {pid}");
|
debug!("forwarding signals to pid {pid}");
|
||||||
|
|
||||||
let pid = Pid::from_raw(pid);
|
let pid = Pid::from_raw(pid);
|
||||||
let signals = [
|
let signals = [
|
||||||
@@ -219,7 +217,7 @@ fn forward_signals_to(pid: i32) {
|
|||||||
};
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
register(sig, move || {
|
register(sig, move || {
|
||||||
log::debug!("forwarding {signal} to {pid}");
|
debug!("forwarding {signal} to {pid}");
|
||||||
let _ = kill(pid, signal);
|
let _ = kill(pid, signal);
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
@@ -319,14 +317,14 @@ async fn compress(path: impl AsRef<Path>) {
|
|||||||
let mut out = ZstdEncoder::new(out);
|
let mut out = ZstdEncoder::new(out);
|
||||||
async {
|
async {
|
||||||
tokio::io::copy(&mut input, &mut out).await?;
|
tokio::io::copy(&mut input, &mut out).await?;
|
||||||
out.flush().await
|
out.shutdown().await
|
||||||
}
|
}
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format_err!("compression of {path_str} failed: {e}"))?;
|
.map_err(|e| format_err!("compression of {path_str} failed: {e}"))?;
|
||||||
|
|
||||||
fs::remove_file(path)
|
fs::remove_file(path)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format_err!("remove {path_str} failed: {e}"))
|
.map_err(|e| format_err!("remove {path_str} failed: {e}"))
|
||||||
}
|
}
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@@ -336,8 +334,9 @@ async fn compress(path: impl AsRef<Path>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_ts(ts: &str) -> std::result::Result<Timestamp, chrono::ParseError> {
|
pub fn parse_ts(ts: &str) -> std::result::Result<Timestamp, chrono::ParseError> {
|
||||||
let dt =
|
let format = &format!("{TS_FORMAT}%M%S");
|
||||||
chrono::NaiveDateTime::parse_from_str(&format!("{ts}0000"), &format!("{TS_FORMAT}%M%S"))?;
|
let full_ts = &format!("{ts}0000");
|
||||||
|
let dt = chrono::NaiveDateTime::parse_from_str(full_ts, format)?;
|
||||||
Ok(Timestamp::from_naive_utc_and_offset(dt, Utc))
|
Ok(Timestamp::from_naive_utc_and_offset(dt, Utc))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,16 +388,27 @@ pub async fn log_files(log_path: &str, log_name: &str) -> fs::Result<Vec<LogFile
|
|||||||
Ok(entries)
|
Ok(entries)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Ord)]
|
#[derive(Debug)]
|
||||||
pub struct LogFile {
|
pub struct LogFile {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
pub compressed: bool,
|
pub compressed: bool,
|
||||||
pub timestamp: Timestamp,
|
pub timestamp: Timestamp,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Eq for LogFile {}
|
||||||
|
impl PartialEq for LogFile {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.timestamp == other.timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Ord for LogFile {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.timestamp.cmp(&other.timestamp)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl PartialOrd for LogFile {
|
impl PartialOrd for LogFile {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
self.timestamp.partial_cmp(&other.timestamp)
|
Some(self.cmp(other))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user