@@ -103,6 +103,7 @@ pub struct RollingWriter<'a>(RwLockReadGuard<'a, File>);
103
103
struct Inner {
104
104
log_directory : PathBuf ,
105
105
log_filename_prefix : Option < String > ,
106
+ log_filename_suffix : Option < String > ,
106
107
rotation : Rotation ,
107
108
next_date : AtomicUsize ,
108
109
}
@@ -170,6 +171,7 @@ impl RollingFileAppender {
170
171
/// let file_appender = RollingFileAppender::builder()
171
172
/// .rotation(Rotation::HOURLY) // rotate log files once every hour
172
173
/// .filename_prefix("myapp") // log file names will be prefixed with `myapp.`
174
+ /// .filename_suffix("log") // log file names will be suffixed with `.log`
173
175
/// .build("/var/log") // try to build an appender that stores log files in `/var/log`
174
176
/// .expect("initializing rolling file appender failed");
175
177
/// # drop(file_appender);
@@ -184,11 +186,17 @@ impl RollingFileAppender {
184
186
let Builder {
185
187
ref rotation,
186
188
ref prefix,
189
+ ref suffix,
187
190
} = builder;
188
- let filename_prefix = prefix. clone ( ) ;
189
191
let directory = directory. as_ref ( ) . to_path_buf ( ) ;
190
192
let now = OffsetDateTime :: now_utc ( ) ;
191
- let ( state, writer) = Inner :: new ( now, rotation. clone ( ) , directory, filename_prefix) ?;
193
+ let ( state, writer) = Inner :: new (
194
+ now,
195
+ rotation. clone ( ) ,
196
+ directory,
197
+ prefix. clone ( ) ,
198
+ suffix. clone ( ) ,
199
+ ) ?;
192
200
Ok ( Self {
193
201
state,
194
202
writer,
@@ -480,42 +488,31 @@ impl Rotation {
480
488
}
481
489
}
482
490
483
- pub ( crate ) fn join_date ( & self , filename : Option < & str > , date : & OffsetDateTime ) -> String {
484
- let date = match * self {
485
- Rotation :: MINUTELY => {
486
- let format = format_description:: parse ( "[year]-[month]-[day]-[hour]-[minute]" )
487
- . expect ( "Unable to create a formatter; this is a bug in tracing-appender" ) ;
488
- date. format ( & format)
489
- . expect ( "Unable to format OffsetDateTime; this is a bug in tracing-appender" )
490
- }
491
- Rotation :: HOURLY => {
492
- let format = format_description:: parse ( "[year]-[month]-[day]-[hour]" )
493
- . expect ( "Unable to create a formatter; this is a bug in tracing-appender" ) ;
494
- date. format ( & format)
495
- . expect ( "Unable to format OffsetDateTime; this is a bug in tracing-appender" )
496
- }
497
- Rotation :: DAILY => {
498
- let format = format_description:: parse ( "[year]-[month]-[day]" )
499
- . expect ( "Unable to create a formatter; this is a bug in tracing-appender" ) ;
500
- date. format ( & format)
501
- . expect ( "Unable to format OffsetDateTime; this is a bug in tracing-appender" )
502
- }
503
- Rotation :: NEVER => {
504
- // If there's a name prefix, use that.
505
- if let Some ( filename) = filename {
506
- return filename. to_owned ( ) ;
507
- }
508
-
509
- // Otherwise, just use the date.
510
- let format = format_description:: parse ( "[year]-[month]-[day]" )
511
- . expect ( "Unable to create a formatter; this is a bug in tracing-appender" ) ;
512
- date. format ( & format)
513
- . expect ( "Unable to format OffsetDateTime; this is a bug in tracing-appender" )
514
- }
515
- } ;
516
- match filename {
517
- Some ( filename) => format ! ( "{}.{}" , filename, date) ,
518
- None => date,
491
+ pub ( crate ) fn join_date (
492
+ & self ,
493
+ filename : Option < & str > ,
494
+ date : & OffsetDateTime ,
495
+ suffix : Option < & str > ,
496
+ ) -> String {
497
+ let format = match * self {
498
+ Rotation :: MINUTELY => format_description:: parse ( "[year]-[month]-[day]-[hour]-[minute]" ) ,
499
+ Rotation :: HOURLY => format_description:: parse ( "[year]-[month]-[day]-[hour]" ) ,
500
+ Rotation :: DAILY => format_description:: parse ( "[year]-[month]-[day]" ) ,
501
+ Rotation :: NEVER => format_description:: parse ( "[year]-[month]-[day]" ) ,
502
+ }
503
+ . expect ( "Unable to create a formatter; this is a bug in tracing-appender" ) ;
504
+ let date = date
505
+ . format ( & format)
506
+ . expect ( "Unable to format OffsetDateTime; this is a bug in tracing-appender" ) ;
507
+
508
+ match ( self , filename, suffix) {
509
+ ( & Rotation :: NEVER , Some ( filename) , None ) => filename. to_string ( ) ,
510
+ ( & Rotation :: NEVER , Some ( filename) , Some ( suffix) ) => format ! ( "{}.{}" , filename, suffix) ,
511
+ ( & Rotation :: NEVER , None , Some ( suffix) ) => suffix. to_string ( ) ,
512
+ ( _, Some ( filename) , Some ( suffix) ) => format ! ( "{}.{}.{}" , filename, date, suffix) ,
513
+ ( _, Some ( filename) , None ) => format ! ( "{}.{}" , filename, date) ,
514
+ ( _, None , Some ( suffix) ) => format ! ( "{}.{}" , date, suffix) ,
515
+ ( _, None , None ) => date,
519
516
}
520
517
}
521
518
}
@@ -540,15 +537,21 @@ impl Inner {
540
537
rotation : Rotation ,
541
538
directory : impl AsRef < Path > ,
542
539
log_filename_prefix : Option < String > ,
540
+ log_filename_suffix : Option < String > ,
543
541
) -> Result < ( Self , RwLock < File > ) , builder:: InitError > {
544
542
let log_directory = directory. as_ref ( ) . to_path_buf ( ) ;
545
- let filename = rotation. join_date ( log_filename_prefix. as_deref ( ) , & now) ;
543
+ let filename = rotation. join_date (
544
+ log_filename_prefix. as_deref ( ) ,
545
+ & now,
546
+ log_filename_suffix. as_deref ( ) ,
547
+ ) ;
546
548
let next_date = rotation. next_date ( & now) ;
547
549
let writer = RwLock :: new ( create_writer ( log_directory. as_ref ( ) , & filename) ?) ;
548
550
549
551
let inner = Inner {
550
552
log_directory,
551
553
log_filename_prefix,
554
+ log_filename_suffix,
552
555
next_date : AtomicUsize :: new (
553
556
next_date
554
557
. map ( |date| date. unix_timestamp ( ) as usize )
@@ -560,9 +563,11 @@ impl Inner {
560
563
}
561
564
562
565
fn refresh_writer ( & self , now : OffsetDateTime , file : & mut File ) {
563
- let filename = self
564
- . rotation
565
- . join_date ( self . log_filename_prefix . as_deref ( ) , & now) ;
566
+ let filename = self . rotation . join_date (
567
+ self . log_filename_prefix . as_deref ( ) ,
568
+ & now,
569
+ self . log_filename_suffix . as_deref ( ) ,
570
+ ) ;
566
571
567
572
match create_writer ( & self . log_directory , & filename) {
568
573
Ok ( new_file) => {
@@ -732,19 +737,51 @@ mod test {
732
737
let now = OffsetDateTime :: parse ( "2020-02-01 10:01:00 +00:00:00" , & format) . unwrap ( ) ;
733
738
734
739
// per-minute
735
- let path = Rotation :: MINUTELY . join_date ( Some ( "app.log" ) , & now) ;
740
+ let path = Rotation :: MINUTELY . join_date ( Some ( "app.log" ) , & now, None ) ;
736
741
assert_eq ! ( "app.log.2020-02-01-10-01" , path) ;
737
742
738
743
// per-hour
739
- let path = Rotation :: HOURLY . join_date ( Some ( "app.log" ) , & now) ;
744
+ let path = Rotation :: HOURLY . join_date ( Some ( "app.log" ) , & now, None ) ;
740
745
assert_eq ! ( "app.log.2020-02-01-10" , path) ;
741
746
742
747
// per-day
743
- let path = Rotation :: DAILY . join_date ( Some ( "app.log" ) , & now) ;
748
+ let path = Rotation :: DAILY . join_date ( Some ( "app.log" ) , & now, None ) ;
744
749
assert_eq ! ( "app.log.2020-02-01" , path) ;
745
750
746
751
// never
747
- let path = Rotation :: NEVER . join_date ( Some ( "app.log" ) , & now) ;
752
+ let path = Rotation :: NEVER . join_date ( Some ( "app.log" ) , & now, None ) ;
753
+ assert_eq ! ( "app.log" , path) ;
754
+
755
+ // per-minute with suffix
756
+ let path = Rotation :: MINUTELY . join_date ( Some ( "app" ) , & now, Some ( "log" ) ) ;
757
+ assert_eq ! ( "app.2020-02-01-10-01.log" , path) ;
758
+
759
+ // per-hour with suffix
760
+ let path = Rotation :: HOURLY . join_date ( Some ( "app" ) , & now, Some ( "log" ) ) ;
761
+ assert_eq ! ( "app.2020-02-01-10.log" , path) ;
762
+
763
+ // per-day with suffix
764
+ let path = Rotation :: DAILY . join_date ( Some ( "app" ) , & now, Some ( "log" ) ) ;
765
+ assert_eq ! ( "app.2020-02-01.log" , path) ;
766
+
767
+ // never with suffix
768
+ let path = Rotation :: NEVER . join_date ( Some ( "app" ) , & now, Some ( "log" ) ) ;
769
+ assert_eq ! ( "app.log" , path) ;
770
+
771
+ // per-minute without prefix
772
+ let path = Rotation :: MINUTELY . join_date ( None , & now, Some ( "app.log" ) ) ;
773
+ assert_eq ! ( "2020-02-01-10-01.app.log" , path) ;
774
+
775
+ // per-hour without prefix
776
+ let path = Rotation :: HOURLY . join_date ( None , & now, Some ( "app.log" ) ) ;
777
+ assert_eq ! ( "2020-02-01-10.app.log" , path) ;
778
+
779
+ // per-day without prefix
780
+ let path = Rotation :: DAILY . join_date ( None , & now, Some ( "app.log" ) ) ;
781
+ assert_eq ! ( "2020-02-01.app.log" , path) ;
782
+
783
+ // never without prefix
784
+ let path = Rotation :: NEVER . join_date ( None , & now, Some ( "app.log" ) ) ;
748
785
assert_eq ! ( "app.log" , path) ;
749
786
}
750
787
@@ -766,6 +803,7 @@ mod test {
766
803
Rotation :: HOURLY ,
767
804
directory. path ( ) ,
768
805
Some ( "test_make_writer" . to_string ( ) ) ,
806
+ None ,
769
807
)
770
808
. unwrap ( ) ;
771
809
0 commit comments