use chrono::prelude::*; use std::{ env::args, fs::File, io::{ stdin, stdout, Error as IoError, ErrorKind, Read, StdoutLock, Write, }, }; type LogtimesResult = Result<(), IoError>; #[inline(always)] fn print_time(output: &mut T) -> LogtimesResult where T: Write, { let date_now = Local::now().format("%H:%M:%S%.6f"); write!(output, "[{}] ", &date_now) } #[inline(always)] fn print_time_color(output: &mut StdoutLock) -> Result<(), std::io::Error> { let date_now = Local::now().format("%H:%M:%S%.6f"); let color_green = "\x1b\x5b\x30\x3b\x33\x32\x6d"; let color_off = "\x1b\x5b\x30\x6d"; write!(output, "{}[{}]{} ", color_green, &date_now, color_off) } #[inline(always)] fn print_delete_line(output: &mut StdoutLock) -> LogtimesResult { // tput dl1 und tput hpa 0 let bytes = "\x1b\x5b\x4d\x1b\x5b\x31\x47"; write!(output, "{}", bytes) } fn run() -> LogtimesResult { let mut log_file = args().nth(1).map(|f| { File::options() .create(true) .append(true) .open(f) .expect("Could not open log file") }); let out = stdout(); let mut output = out.lock(); let inp = stdin(); let mut input = inp.lock(); let mut buf = [0; 1]; let mut linebuf = Vec::with_capacity(64 * 1024); loop { // read 1 char if let Err(e) = input.read_exact(&mut buf) { if e.kind() == ErrorKind::UnexpectedEof { return Ok(()); } else { return Err(e); } } // push that char to the "current line" buffer linebuf.push(buf[0]); // 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 if buf[0] == 0xa { print_delete_line(&mut output)?; print_time_color(&mut output)?; output.write_all(&linebuf)?; output.flush()?; if let Some(ref mut f) = log_file { print_time(f)?; f.write_all(&linebuf)?; f.flush()?; }; // clear line buffer so it is fresh for the next line linebuf.clear(); continue; } output.write_all(&buf)?; output.flush()?; } } fn main() { if let Err(e) = run() { println!("{:?}", e); std::process::exit(1); } }