@@ -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,38 @@ 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
- }
491
+ pub ( crate ) fn join_date (
492
+ & self ,
493
+ filename : Option < & str > ,
494
+ date : & OffsetDateTime ,
495
+ suffix : Option < & str > ,
496
+ ) -> String {
497
+ let format = self . get_date_format ( ) ;
498
+ let date = date
499
+ . format ( & format)
500
+ . expect ( "Unable to format OffsetDateTime; this is a bug in tracing-appender" ) ;
501
+
502
+ match ( self , filename, suffix) {
503
+ ( & Rotation :: NEVER , Some ( filename) , None ) => filename. to_string ( ) ,
504
+ ( & Rotation :: NEVER , Some ( filename) , Some ( suffix) ) => format ! ( "{}.{}" , filename, suffix) ,
505
+ ( & Rotation :: NEVER , None , Some ( suffix) ) => suffix. to_string ( ) ,
506
+ ( _, Some ( filename) , Some ( suffix) ) => format ! ( "{}.{}.{}" , filename, date, suffix) ,
507
+ ( _, Some ( filename) , None ) => format ! ( "{}.{}" , filename, date) ,
508
+ ( _, None , Some ( suffix) ) => format ! ( "{}.{}" , date, suffix) ,
509
+ ( _, None , None ) => date,
510
+ }
511
+ }
508
512
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 ,
513
+ fn get_date_format < ' a > ( & self ) -> Vec < format_description :: FormatItem < ' a > > {
514
+ match * self {
515
+ Rotation :: MINUTELY => format_description :: parse ( "[year]-[month]-[day]-[hour]-[minute]" )
516
+ . expect ( "Unable to create a formatter; this is a bug in tracing-appender" ) ,
517
+ Rotation :: HOURLY => format_description :: parse ( "[year]-[month]-[day]-[hour] ")
518
+ . expect ( "Unable to create a formatter; this is a bug in tracing-appender" ) ,
519
+ Rotation :: DAILY => format_description :: parse ( "[year]-[month]-[day]" )
520
+ . expect ( "Unable to create a formatter; this is a bug in tracing-appender" ) ,
521
+ Rotation :: NEVER => format_description :: parse ( "[year]-[month]-[day]" )
522
+ . expect ( "Unable to create a formatter; this is a bug in tracing-appender" ) ,
519
523
}
520
524
}
521
525
}
@@ -540,15 +544,21 @@ impl Inner {
540
544
rotation : Rotation ,
541
545
directory : impl AsRef < Path > ,
542
546
log_filename_prefix : Option < String > ,
547
+ log_filename_suffix : Option < String > ,
543
548
) -> Result < ( Self , RwLock < File > ) , builder:: InitError > {
544
549
let log_directory = directory. as_ref ( ) . to_path_buf ( ) ;
545
- let filename = rotation. join_date ( log_filename_prefix. as_deref ( ) , & now) ;
550
+ let filename = rotation. join_date (
551
+ log_filename_prefix. as_deref ( ) ,
552
+ & now,
553
+ log_filename_suffix. as_deref ( ) ,
554
+ ) ;
546
555
let next_date = rotation. next_date ( & now) ;
547
556
let writer = RwLock :: new ( create_writer ( log_directory. as_ref ( ) , & filename) ?) ;
548
557
549
558
let inner = Inner {
550
559
log_directory,
551
560
log_filename_prefix,
561
+ log_filename_suffix,
552
562
next_date : AtomicUsize :: new (
553
563
next_date
554
564
. map ( |date| date. unix_timestamp ( ) as usize )
@@ -560,9 +570,11 @@ impl Inner {
560
570
}
561
571
562
572
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) ;
573
+ let filename = self . rotation . join_date (
574
+ self . log_filename_prefix . as_deref ( ) ,
575
+ & now,
576
+ self . log_filename_suffix . as_deref ( ) ,
577
+ ) ;
566
578
567
579
match create_writer ( & self . log_directory , & filename) {
568
580
Ok ( new_file) => {
@@ -732,19 +744,51 @@ mod test {
732
744
let now = OffsetDateTime :: parse ( "2020-02-01 10:01:00 +00:00:00" , & format) . unwrap ( ) ;
733
745
734
746
// per-minute
735
- let path = Rotation :: MINUTELY . join_date ( Some ( "app.log" ) , & now) ;
747
+ let path = Rotation :: MINUTELY . join_date ( Some ( "app.log" ) , & now, None ) ;
736
748
assert_eq ! ( "app.log.2020-02-01-10-01" , path) ;
737
749
738
750
// per-hour
739
- let path = Rotation :: HOURLY . join_date ( Some ( "app.log" ) , & now) ;
751
+ let path = Rotation :: HOURLY . join_date ( Some ( "app.log" ) , & now, None ) ;
740
752
assert_eq ! ( "app.log.2020-02-01-10" , path) ;
741
753
742
754
// per-day
743
- let path = Rotation :: DAILY . join_date ( Some ( "app.log" ) , & now) ;
755
+ let path = Rotation :: DAILY . join_date ( Some ( "app.log" ) , & now, None ) ;
744
756
assert_eq ! ( "app.log.2020-02-01" , path) ;
745
757
746
758
// never
747
- let path = Rotation :: NEVER . join_date ( Some ( "app.log" ) , & now) ;
759
+ let path = Rotation :: NEVER . join_date ( Some ( "app.log" ) , & now, None ) ;
760
+ assert_eq ! ( "app.log" , path) ;
761
+
762
+ // per-minute with suffix
763
+ let path = Rotation :: MINUTELY . join_date ( Some ( "app" ) , & now, Some ( "log" ) ) ;
764
+ assert_eq ! ( "app.2020-02-01-10-01.log" , path) ;
765
+
766
+ // per-hour with suffix
767
+ let path = Rotation :: HOURLY . join_date ( Some ( "app" ) , & now, Some ( "log" ) ) ;
768
+ assert_eq ! ( "app.2020-02-01-10.log" , path) ;
769
+
770
+ // per-day with suffix
771
+ let path = Rotation :: DAILY . join_date ( Some ( "app" ) , & now, Some ( "log" ) ) ;
772
+ assert_eq ! ( "app.2020-02-01.log" , path) ;
773
+
774
+ // never with suffix
775
+ let path = Rotation :: NEVER . join_date ( Some ( "app" ) , & now, Some ( "log" ) ) ;
776
+ assert_eq ! ( "app.log" , path) ;
777
+
778
+ // per-minute without prefix
779
+ let path = Rotation :: MINUTELY . join_date ( None , & now, Some ( "app.log" ) ) ;
780
+ assert_eq ! ( "2020-02-01-10-01.app.log" , path) ;
781
+
782
+ // per-hour without prefix
783
+ let path = Rotation :: HOURLY . join_date ( None , & now, Some ( "app.log" ) ) ;
784
+ assert_eq ! ( "2020-02-01-10.app.log" , path) ;
785
+
786
+ // per-day without prefix
787
+ let path = Rotation :: DAILY . join_date ( None , & now, Some ( "app.log" ) ) ;
788
+ assert_eq ! ( "2020-02-01.app.log" , path) ;
789
+
790
+ // never without prefix
791
+ let path = Rotation :: NEVER . join_date ( None , & now, Some ( "app.log" ) ) ;
748
792
assert_eq ! ( "app.log" , path) ;
749
793
}
750
794
@@ -766,6 +810,7 @@ mod test {
766
810
Rotation :: HOURLY ,
767
811
directory. path ( ) ,
768
812
Some ( "test_make_writer" . to_string ( ) ) ,
813
+ None ,
769
814
)
770
815
. unwrap ( ) ;
771
816
0 commit comments