Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 11, 08:30 UTC
log: support `d` (day) in `roll_interval` directive (#7900)
Signed-off-by: Mohammed Al Sahaf <msaa1990@gmail.com>
Mohammed Al Sahaf committed
Jul 22, 2026 at 01:39 UTC
31daa220fcba80c7ed7ea636e7f04c568c8cccf8
2 files changed
+71
-4
modules/logging/filewriter.go
+4
-4
@@ -108,7 +108,7 @@ type FileWriter struct {
108
RollSizeMB int `json:"roll_size_mb,omitempty"`
109
110
// Roll log file after some time
111
- RollInterval time.Duration `json:"roll_interval,omitempty"`
111
+ RollInterval caddy.Duration `json:"roll_interval,omitempty"`
112
113
// Roll log file at fix minutes
114
// For example []int{0, 30} will roll file at xx:00 and xx:30 each hour
@@ -287,7 +287,7 @@ func (fw FileWriter) OpenWriter() (io.WriteCloser, error) {
287
MaxBackups: fw.RollKeep,
288
LocalTime: fw.RollLocalTime,
289
Compression: compression,
290
- RotationInterval: fw.RollInterval,
290
+ RotationInterval: time.Duration(fw.RollInterval),
291
RotateAtMinutes: fw.RollAtMinutes,
292
RotateAt: fw.RollAt,
293
BackupTimeFormat: fw.BackupTimeFormat,
@@ -489,11 +489,11 @@ func (fw *FileWriter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
489
if !d.AllArgs(&durationStr) {
490
return d.ArgErr()
491
}
492
- duration, err := time.ParseDuration(durationStr)
492
+ duration, err := caddy.ParseDuration(durationStr)
493
if err != nil {
494
return d.Errf("parsing roll_interval duration: %v", err)
495
}
496
- fw.RollInterval = duration
496
+ fw.RollInterval = caddy.Duration(duration)
497
498
case "roll_minutes":
499
// Accept either a single comma-separated argument or
modules/logging/filewriter_test.go
+67
@@ -23,6 +23,7 @@ import (
23
"path/filepath"
24
"syscall"
25
"testing"
26
+ "time"
27
28
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
29
)
@@ -648,3 +649,69 @@ file /var/log/app.log {
649
t.Fatal("expected error for invalid dir_mode")
650
}
651
}
652
+
653
+func TestCaddyfile_RollInterval(t *testing.T) {
654
+ tests := []struct {
655
+ name string
656
+ input string
657
+ wantSecs float64
658
+ wantErr bool
659
+ }{
660
+ {
661
+ name: "day unit",
662
+ input: `file /var/log/app.log {
663
+ roll_interval 1d
664
+}`,
665
+ wantSecs: 86400,
666
+ },
667
+ {
668
+ name: "hours unit",
669
+ input: `file /var/log/app.log {
670
+ roll_interval 24h
671
+}`,
672
+ wantSecs: 86400,
673
+ },
674
+ {
675
+ name: "minutes unit",
676
+ input: `file /var/log/app.log {
677
+ roll_interval 30m
678
+}`,
679
+ wantSecs: 1800,
680
+ },
681
+ {
682
+ name: "fractional days",
683
+ input: `file /var/log/app.log {
684
+ roll_interval 1.5d
685
+}`,
686
+ wantSecs: 129600,
687
+ },
688
+ {
689
+ name: "invalid duration",
690
+ input: `file /var/log/app.log {
691
+ roll_interval bogus
692
+}`,
693
+ wantErr: true,
694
+ },
695
+ }
696
+
697
+ for _, tt := range tests {
698
+ t.Run(tt.name, func(t *testing.T) {
699
+ d := caddyfile.NewTestDispenser(tt.input)
700
+ var fw FileWriter
701
+ err := fw.UnmarshalCaddyfile(d)
702
+ if tt.wantErr {
703
+ if err == nil {
704
+ t.Fatal("expected error but got none")
705
+ }
706
+ return
707
+ }
708
+ if err != nil {
709
+ t.Fatalf("unexpected error: %v", err)
710
+ }
711
+ gotSecs := time.Duration(fw.RollInterval).Seconds()
712
+ if gotSecs != tt.wantSecs {
713
+ t.Errorf("got %v seconds, want %v", gotSecs, tt.wantSecs)
714
+ }
715
+ })
716
+ }
717
+}