@@ -2,7 +2,7 @@ use std::env;
22use std:: io:: { self , BufRead , BufReader , Write , BufWriter } ;
33use std:: path:: Path ;
44use std:: time:: { SystemTime , UNIX_EPOCH , Instant } ;
5- use std:: fs:: { File , create_dir_all } ;
5+ use std:: fs:: { create_dir_all , OpenOptions } ;
66use chrono:: { DateTime , Local , Utc , TimeZone , Timelike , Datelike } ;
77
88struct Config {
@@ -21,6 +21,7 @@ struct Config {
2121 buffered : bool ,
2222 timezone : Option < String > ,
2323 output_file : Option < String > ,
24+ force_overwrite : bool ,
2425}
2526
2627impl Config {
@@ -41,6 +42,7 @@ impl Config {
4142 buffered : false , // Default to unbuffered for real-time output
4243 timezone : None ,
4344 output_file : None ,
45+ force_overwrite : false ,
4446 } ;
4547
4648 let args: Vec < String > = env:: args ( ) . collect ( ) ;
@@ -67,6 +69,7 @@ impl Config {
6769 "--prefix-only" => config. prefix_only = true ,
6870 "--color" => config. color = true ,
6971 "--buffered" => config. buffered = true ,
72+ "--force-overwrite" => config. force_overwrite = true ,
7073 "-s" | "--separator" => {
7174 i += 1 ;
7275 if i >= args. len ( ) {
@@ -134,27 +137,28 @@ impl Config {
134137
135138 fn print_help ( program_name : & str ) {
136139 println ! (
137- "{} - timestamp each line of input
140+ "{} - timestamp each line of input stream
138141
139142Usage: {} [OPTIONS]
140143
141144Options:
145+ --buffered Use buffered output (default is unbuffered)
146+ --color Colorize timestamps
147+ --delta Show time delta between lines
148+ -e, --epoch Show seconds since Unix epoch
142149 -f, --format FORMAT Date format (default: %Y-%m-%d %H:%M:%S)
143- -s, --separator SEP Separator between timestamp and line (default: \" \" )
144- -r, --relative Show relative timestamps from start
145- -m, --monotonic Use monotonic clock for relative timestamps
146- -u, --utc Use UTC time instead of local time
150+ --force-overwrite Overwrite output file instead of appending
147151 -i, --iso Use ISO 8601 format (2025-07-03T14:30:45.123+05:45)
148- -e , --epoch Show seconds since Unix epoch
152+ -h , --help Show this help
149153 --microseconds Show microseconds precision
154+ -m, --monotonic Use monotonic clock for relative timestamps
150155 --nanoseconds Show nanoseconds precision
151- --delta Show time delta between lines
156+ -o, --output FILE Write timestamped output to file (appends by default)
152157 --prefix-only Only show timestamp prefix (no input lines)
153- --color Colorize timestamps
154- --buffered Use buffered output (default is unbuffered )
158+ -r, --relative Show relative timestamps from start
159+ -s, --separator SEP Separator between timestamp and line (default: \" \" )
155160 --timezone TZ Use specific timezone (e.g., UTC, EST, PST)
156- -o, --output FILE Write timestamped output to file (creates directories)
157- -h, --help Show this help
161+ -u, --utc Use UTC time instead of local time
158162
159163Format specifiers (strftime compatible):
160164 %Y 4-digit year %m Month (01-12) %d Day (01-31)
@@ -163,22 +167,24 @@ Format specifiers (strftime compatible):
163167 %z Timezone offset %Z Timezone name %% Literal %
164168
165169Examples:
166- ls -la | {} # Basic timestamping
167- tail -f /var/log/messages | {} -r # Relative timestamps
168- ping google.com | {} -f \" [%H:%M:%S.%3f]\" # Custom format
169- dmesg | {} -i # ISO format
170- make 2>&1 | {} -e # Epoch timestamps
171- tail -f app.log | {} -r -m # Relative monotonic
172- cat file.txt | {} --delta # Show time between lines
173- ping host | {} --color --microseconds # Colored with microseconds
174- 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
170+ ls -la | {} # Basic timestamping
171+ tail -f /var/log/messages | {} -r # Relative timestamps
172+ ping google.com | {} -f \" [%H:%M:%S.%3f]➜ \" # Custom format
173+ dmesg | {} -i # ISO format
174+ make 2>&1 | {} -e # Epoch timestamps
175+ tail -f app.log | {} -r -m # Relative monotonic
176+ cat file.txt | {} --delta # Show time between lines
177+ ping host | {} --color --microseconds # Colored with microseconds
178+ command | {} --prefix-only # Only timestamps
179+ make 2>&1 | {} -o build.log # Append to file
180+ tail -f app.log | {} -o logs/app.log --force-overwrite # Overwrite file
181+ ping host | {} -o network.log # Append to network.log
177182
178- Note: --relative and --delta are mutually exclusive" ,
183+ Note: --relative and --delta are mutually exclusive
184+ Output files are appended to by default, use --force-overwrite to replace\n " ,
179185 program_name, program_name, program_name, program_name, program_name,
180186 program_name, program_name, program_name, program_name, program_name,
181- program_name, program_name, program_name
187+ program_name, program_name, program_name, program_name
182188 ) ;
183189 }
184190}
@@ -528,7 +534,23 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
528534 if let Some ( parent) = Path :: new ( output_path) . parent ( ) {
529535 create_dir_all ( parent) ?;
530536 }
531- Some ( BufWriter :: new ( File :: create ( output_path) ?) )
537+
538+ // Open file for writing (append by default, create/truncate if force_overwrite)
539+ let file = if config. force_overwrite {
540+ OpenOptions :: new ( )
541+ . create ( true )
542+ . write ( true )
543+ . truncate ( true )
544+ . open ( output_path) ?
545+ } else {
546+ OpenOptions :: new ( )
547+ . create ( true )
548+ . write ( true )
549+ . append ( true )
550+ . open ( output_path) ?
551+ } ;
552+
553+ Some ( BufWriter :: new ( file) )
532554 } else {
533555 None
534556 } ;
0 commit comments