2022-08-04 08:55:50 +02:00
|
|
|
use std::{
|
|
|
|
env::args,
|
|
|
|
fs::File,
|
2023-07-12 12:39:55 +02:00
|
|
|
io::{stdin, stdout, Error as IoError, ErrorKind, Read, Write},
|
2022-08-04 08:55:50 +02:00
|
|
|
};
|
|
|
|
|
2023-07-12 12:39:55 +02:00
|
|
|
use chrono::prelude::*;
|
|
|
|
|
2022-08-12 17:33:06 +02:00
|
|
|
const TIME_FORMAT: &str = "%H:%M:%S%.6f";
|
|
|
|
|
2022-08-04 08:55:50 +02:00
|
|
|
type LogtimesResult = Result<(), IoError>;
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
fn print_time<T>(output: &mut T) -> LogtimesResult
|
|
|
|
where
|
|
|
|
T: Write,
|
|
|
|
{
|
2022-08-12 17:33:06 +02:00
|
|
|
let date_now = Local::now().format(TIME_FORMAT);
|
2022-08-04 08:55:50 +02:00
|
|
|
|
|
|
|
write!(output, "[{}] ", &date_now)
|
|
|
|
}
|
2020-07-30 10:15:18 +02:00
|
|
|
|
|
|
|
#[inline(always)]
|
2023-01-02 15:37:44 +01:00
|
|
|
fn print_time_color<T>(output: &mut T) -> Result<(), std::io::Error>
|
|
|
|
where
|
|
|
|
T: Write,
|
|
|
|
{
|
2022-08-12 17:33:06 +02:00
|
|
|
let date_now = Local::now().format(TIME_FORMAT);
|
2020-07-30 10:15:18 +02:00
|
|
|
|
|
|
|
let color_green = "\x1b\x5b\x30\x3b\x33\x32\x6d";
|
|
|
|
let color_off = "\x1b\x5b\x30\x6d";
|
|
|
|
|
2022-08-03 13:10:14 +02:00
|
|
|
write!(output, "{}[{}]{} ", color_green, &date_now, color_off)
|
2020-07-30 10:15:18 +02:00
|
|
|
}
|
|
|
|
|
2022-08-03 13:10:14 +02:00
|
|
|
#[inline(always)]
|
2023-01-02 15:37:44 +01:00
|
|
|
fn print_delete_line<T>(output: &mut T) -> LogtimesResult
|
|
|
|
where
|
|
|
|
T: Write,
|
|
|
|
{
|
2022-08-03 13:10:14 +02:00
|
|
|
// tput dl1 und tput hpa 0
|
|
|
|
let bytes = "\x1b\x5b\x4d\x1b\x5b\x31\x47";
|
2023-02-03 11:53:22 +01:00
|
|
|
write!(output, "{bytes}")
|
2022-08-03 13:10:14 +02:00
|
|
|
}
|
2020-07-30 10:15:18 +02:00
|
|
|
|
2023-04-05 17:51:06 +02:00
|
|
|
fn trim_end(line: &[u8]) -> usize {
|
|
|
|
let mut end = line.len();
|
2024-03-05 18:53:26 +01:00
|
|
|
line.iter()
|
|
|
|
.rev()
|
|
|
|
.take_while(|ch| ch.is_ascii_whitespace())
|
|
|
|
.for_each(|_| end -= 1);
|
2023-04-05 17:51:06 +02:00
|
|
|
end
|
|
|
|
}
|
|
|
|
|
2022-08-04 08:55:50 +02:00
|
|
|
fn run() -> LogtimesResult {
|
2022-08-04 18:50:07 +02:00
|
|
|
let mut log_file = args().nth(1).map(|f| {
|
|
|
|
File::options()
|
|
|
|
.create(true)
|
|
|
|
.append(true)
|
|
|
|
.open(f)
|
|
|
|
.expect("Could not open log file")
|
|
|
|
});
|
2022-08-04 08:55:50 +02:00
|
|
|
|
2023-01-02 15:37:44 +01:00
|
|
|
let mut out = stdout().lock();
|
|
|
|
let mut inp = stdin().lock();
|
2020-07-30 10:15:18 +02:00
|
|
|
|
2022-08-03 13:10:14 +02:00
|
|
|
let mut buf = [0; 1];
|
2020-07-30 10:15:18 +02:00
|
|
|
|
2022-08-03 13:10:14 +02:00
|
|
|
let mut linebuf = Vec::with_capacity(64 * 1024);
|
2020-07-30 10:15:18 +02:00
|
|
|
|
2022-08-03 13:10:14 +02:00
|
|
|
loop {
|
2022-08-04 08:55:50 +02:00
|
|
|
// read 1 char
|
2023-01-02 15:37:44 +01:00
|
|
|
if let Err(e) = inp.read_exact(&mut buf) {
|
2022-08-04 18:50:47 +02:00
|
|
|
if e.kind() == ErrorKind::UnexpectedEof {
|
|
|
|
return Ok(());
|
|
|
|
}
|
2023-07-12 12:39:55 +02:00
|
|
|
return Err(e);
|
2022-08-04 18:50:47 +02:00
|
|
|
}
|
2020-07-30 10:15:18 +02:00
|
|
|
|
2022-08-04 08:55:50 +02:00
|
|
|
// push that char to the "current line" buffer
|
2022-08-03 13:10:14 +02:00
|
|
|
linebuf.push(buf[0]);
|
2020-07-30 10:15:18 +02:00
|
|
|
|
2022-08-04 08:55:50 +02:00
|
|
|
// we encounter a newline -> delete the line and write it new as:
|
|
|
|
// [timestamp] actual content\n
|
|
|
|
// also write the line to the log file if there is one
|
2020-07-30 10:15:18 +02:00
|
|
|
if buf[0] == 0xa {
|
2023-01-02 15:37:44 +01:00
|
|
|
print_delete_line(&mut out)?;
|
|
|
|
print_time_color(&mut out)?;
|
2023-04-05 17:51:06 +02:00
|
|
|
|
|
|
|
let end = trim_end(&linebuf);
|
|
|
|
out.write_all(&linebuf[..end])?;
|
|
|
|
out.write_all(&[b'\r', b'\n'])?;
|
2023-01-02 15:37:44 +01:00
|
|
|
out.flush()?;
|
2022-08-03 13:10:14 +02:00
|
|
|
|
2022-08-04 08:55:50 +02:00
|
|
|
if let Some(ref mut f) = log_file {
|
|
|
|
print_time(f)?;
|
2023-04-05 17:51:06 +02:00
|
|
|
f.write_all(&linebuf[..end])?;
|
|
|
|
f.write_all(&[b'\n'])?;
|
2022-08-04 08:55:50 +02:00
|
|
|
f.flush()?;
|
|
|
|
};
|
|
|
|
|
2024-02-09 18:26:10 +01:00
|
|
|
// clear line buffer, so it is fresh for the next line
|
2022-08-03 13:10:14 +02:00
|
|
|
linebuf.clear();
|
2020-07-30 10:15:18 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-01-02 15:37:44 +01:00
|
|
|
out.write_all(&buf)?;
|
|
|
|
out.flush()?;
|
2022-08-03 13:10:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
if let Err(e) = run() {
|
2023-02-03 11:53:22 +01:00
|
|
|
println!("{e:?}");
|
2022-08-03 13:10:14 +02:00
|
|
|
std::process::exit(1);
|
2020-07-30 10:15:18 +02:00
|
|
|
}
|
|
|
|
}
|