Skip to content

Commit 0a734ef

Browse files
committed
add
1 parent f20a55c commit 0a734ef

File tree

1 file changed

+78
-10
lines changed

1 file changed

+78
-10
lines changed

Linux/tss/src/main.rs

Lines changed: 78 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::env;
22
use std::io::{self, BufRead, BufReader, Write, BufWriter};
33
use std::path::Path;
44
use std::time::{SystemTime, UNIX_EPOCH, Instant};
5+
use std::fs::{File, create_dir_all};
56
use chrono::{DateTime, Local, Utc, TimeZone, Timelike, Datelike};
67

78
struct Config {
@@ -19,6 +20,7 @@ struct Config {
1920
color: bool,
2021
buffered: bool,
2122
timezone: Option<String>,
23+
output_file: Option<String>,
2224
}
2325

2426
impl Config {
@@ -38,6 +40,7 @@ impl Config {
3840
color: false,
3941
buffered: false, // Default to unbuffered for real-time output
4042
timezone: None,
43+
output_file: None,
4144
};
4245

4346
let args: Vec<String> = env::args().collect();
@@ -88,6 +91,14 @@ impl Config {
8891
}
8992
config.timezone = Some(args[i].clone());
9093
}
94+
"-o" | "--output" => {
95+
i += 1;
96+
if i >= args.len() {
97+
eprintln!("Error: --output requires a value");
98+
std::process::exit(1);
99+
}
100+
config.output_file = Some(args[i].clone());
101+
}
91102
_ => {
92103
eprintln!("Unknown argument: {}", args[i]);
93104
std::process::exit(1);
@@ -142,6 +153,7 @@ Options:
142153
--color Colorize timestamps
143154
--buffered Use buffered output (default is unbuffered)
144155
--timezone TZ Use specific timezone (e.g., UTC, EST, PST)
156+
-o, --output FILE Write timestamped output to file (creates directories)
145157
-h, --help Show this help
146158
147159
Format specifiers (strftime compatible):
@@ -160,10 +172,13 @@ Examples:
160172
cat file.txt | {} --delta # Show time between lines
161173
ping host | {} --color --microseconds # Colored with microseconds
162174
command | {} --prefix-only # Only timestamps
175+
make 2>&1 | {} -o build.log # Stream to console and file
176+
tail -f app.log | {} -o logs/app-timestamped.log # Save to file with directories
163177
164178
Note: --relative and --delta are mutually exclusive",
165179
program_name, program_name, program_name, program_name, program_name,
166-
program_name, program_name, program_name, program_name, program_name, program_name
180+
program_name, program_name, program_name, program_name, program_name,
181+
program_name, program_name, program_name
167182
);
168183
}
169184
}
@@ -272,6 +287,16 @@ impl TimeFormatter {
272287

273288
#[inline]
274289
fn format_timestamp(&mut self, monotonic: bool) -> &str {
290+
self.format_timestamp_impl(monotonic, true)
291+
}
292+
293+
#[inline]
294+
fn format_timestamp_no_color(&mut self, monotonic: bool) -> &str {
295+
self.format_timestamp_impl(monotonic, false)
296+
}
297+
298+
#[inline]
299+
fn format_timestamp_impl(&mut self, monotonic: bool, use_color: bool) -> &str {
275300
self.timestamp_buf.clear();
276301

277302
match &self.format_type {
@@ -283,7 +308,7 @@ impl TimeFormatter {
283308
} else {
284309
// Initialize with current time for first call
285310
self.last_instant = Some(instant);
286-
return if self.color {
311+
return if use_color && self.color {
287312
self.timestamp_buf.push_str(self.color_prefix);
288313
self.timestamp_buf.push_str("0.000000");
289314
self.timestamp_buf.push_str(self.color_suffix);
@@ -301,7 +326,7 @@ impl TimeFormatter {
301326
} else {
302327
// Initialize with current time for first call
303328
self.last_time = Some(time);
304-
return if self.color {
329+
return if use_color && self.color {
305330
self.timestamp_buf.push_str(self.color_prefix);
306331
self.timestamp_buf.push_str("0.000000");
307332
self.timestamp_buf.push_str(self.color_suffix);
@@ -480,7 +505,7 @@ impl TimeFormatter {
480505

481506
// Add color codes if needed - do this outside the timestamp buffer
482507
// to avoid reallocation on every call
483-
if self.color {
508+
if use_color && self.color {
484509
// Create a temporary string with color codes
485510
let colored = format!("{}{}{}", self.color_prefix, self.timestamp_buf, self.color_suffix);
486511
self.timestamp_buf = colored;
@@ -497,6 +522,17 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
497522
let stdin = io::stdin();
498523
let stdout = io::stdout();
499524

525+
// Set up output file if specified
526+
let mut file_writer = if let Some(ref output_path) = config.output_file {
527+
// Create parent directories if they don't exist
528+
if let Some(parent) = Path::new(output_path).parent() {
529+
create_dir_all(parent)?;
530+
}
531+
Some(BufWriter::new(File::create(output_path)?))
532+
} else {
533+
None
534+
};
535+
500536
// Use appropriate buffer sizes based on configuration
501537
let buffer_size = if config.buffered { 256 * 1024 } else { 0 };
502538
let reader = BufReader::with_capacity(128 * 1024, stdin);
@@ -509,22 +545,54 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
509545
let line = line_result?;
510546
let timestamp = formatter.format_timestamp(config.monotonic);
511547

512-
// Write timestamp
513-
writer.write_all(timestamp.as_bytes())?;
548+
// Prepare the complete output line
549+
let mut output_line = Vec::new();
550+
output_line.extend_from_slice(timestamp.as_bytes());
514551

515552
if !config.prefix_only {
516-
writer.write_all(separator_bytes)?;
517-
writer.write_all(line.as_bytes())?;
553+
output_line.extend_from_slice(separator_bytes);
554+
output_line.extend_from_slice(line.as_bytes());
518555
}
519556

520-
writer.write_all(newline)?;
557+
output_line.extend_from_slice(newline);
558+
559+
// Write to stdout
560+
writer.write_all(&output_line)?;
561+
562+
// Write to file if specified (without color codes for clean file output)
563+
if let Some(ref mut file_writer) = file_writer {
564+
if config.color {
565+
// Strip color codes for file output
566+
let clean_timestamp = formatter.format_timestamp_no_color(config.monotonic);
567+
let mut clean_output = Vec::new();
568+
clean_output.extend_from_slice(clean_timestamp.as_bytes());
569+
570+
if !config.prefix_only {
571+
clean_output.extend_from_slice(separator_bytes);
572+
clean_output.extend_from_slice(line.as_bytes());
573+
}
574+
575+
clean_output.extend_from_slice(newline);
576+
file_writer.write_all(&clean_output)?;
577+
} else {
578+
file_writer.write_all(&output_line)?;
579+
}
580+
581+
// Flush file writer if not buffered
582+
if !config.buffered {
583+
file_writer.flush()?;
584+
}
585+
}
521586

522-
// Flush when unbuffered
587+
// Flush stdout when unbuffered
523588
if !config.buffered {
524589
writer.flush()?;
525590
}
526591
}
527592

528593
writer.flush()?;
594+
if let Some(ref mut file_writer) = file_writer {
595+
file_writer.flush()?;
596+
}
529597
Ok(())
530598
}

0 commit comments

Comments
 (0)