Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.25

require (
github.com/BurntSushi/toml v1.5.0
github.com/DeRuina/timberjack v1.3.5
github.com/KimMachineGun/automemlimit v0.7.4
github.com/Masterminds/sprig/v3 v3.3.0
github.com/alecthomas/chroma/v2 v2.20.0
Expand Down Expand Up @@ -43,7 +44,6 @@ require (
golang.org/x/sync v0.16.0
golang.org/x/term v0.34.0
golang.org/x/time v0.12.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1
)

Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOv
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/DeRuina/timberjack v1.3.5 h1:a8QrIyFCmnx6sjqmroFTIXcmNcen69dlx8DBRmN8+qU=
github.com/DeRuina/timberjack v1.3.5/go.mod h1:oir/YwhAK3URX7u4CDuMzdVQtLQqc1l3M/vJ6WBsjZs=
github.com/KimMachineGun/automemlimit v0.7.4 h1:UY7QYOIfrr3wjjOAqahFmC3IaQCLWvur9nmfIn6LnWk=
github.com/KimMachineGun/automemlimit v0.7.4/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
Expand Down Expand Up @@ -149,6 +151,8 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
Expand Down Expand Up @@ -663,8 +667,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
Expand Down
85 changes: 75 additions & 10 deletions modules/logging/filewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ import (
"os"
"path/filepath"
"strconv"
"strings"
"time"

"github.com/DeRuina/timberjack"
"github.com/dustin/go-humanize"
"gopkg.in/natefinch/lumberjack.v2"

"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
Expand Down Expand Up @@ -96,6 +98,15 @@ type FileWriter struct {
// it will be rotated.
RollSizeMB int `json:"roll_size_mb,omitempty"`

// Roll log file after some time
RollInterval time.Duration `json:"roll_interval,omitempty"`

// Roll log file at fix minutes
RollAtMinutes []int `json:"roll_at_minutes,omitempty"`

// Roll log file at fix time
RollAt []string `json:"roll_at,omitempty"`
Comment on lines +104 to +108
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These godoc comments should cover some of the caveats mentioned in the timberjack README https://github.com/DeRuina/timberjack#%EF%B8%8F-rotation-notes--warnings (and eventually also in the Caddy website docs)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's also subtleties like using either of RollAt/RollAtMinutes will use a background goroutine to trigger rotation, whereas RollInterval triggers a check on each log write whether the interval has been crossed and causes a rotation at that point (no goroutine).


// Whether to compress rolled files. Default: true
RollCompress *bool `json:"roll_gzip,omitempty"`

Expand All @@ -109,6 +120,9 @@ type FileWriter struct {

// How many days to keep rolled log files. Default: 90
RollKeepDays int `json:"roll_keep_days,omitempty"`

// Rotated file will have format <logfilename>-<format>-<criterion>.log
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should explain that the default from timberjack is:

// Optional. If unset or invalid, defaults to 2006-01-02T15-04-05.000 (with fallback warning)

Also mention that the <format> must be a Go time compatible format described here https://pkg.go.dev/time#pkg-constants

BackupTimeFormat string `json:"backup_time_format,omitempty"`
}

// CaddyModule returns the Caddy module information.
Expand Down Expand Up @@ -156,7 +170,7 @@ func (fw FileWriter) OpenWriter() (io.WriteCloser, error) {
roll := fw.Roll == nil || *fw.Roll

// create the file if it does not exist; create with the configured mode, or default
// to restrictive if not set. (lumberjack will reuse the file mode across log rotation)
// to restrictive if not set. (timberjack will reuse the file mode across log rotation)
if err := os.MkdirAll(filepath.Dir(fw.Filename), 0o700); err != nil {
return nil, err
}
Expand All @@ -166,7 +180,7 @@ func (fw FileWriter) OpenWriter() (io.WriteCloser, error) {
}
info, err := file.Stat()
if roll {
file.Close() // lumberjack will reopen it on its own
file.Close() // timberjack will reopen it on its own
}

// Ensure already existing files have the right mode, since OpenFile will not set the mode in such case.
Expand Down Expand Up @@ -201,13 +215,17 @@ func (fw FileWriter) OpenWriter() (io.WriteCloser, error) {
if fw.RollKeepDays == 0 {
fw.RollKeepDays = 90
}
return &lumberjack.Logger{
Filename: fw.Filename,
MaxSize: fw.RollSizeMB,
MaxAge: fw.RollKeepDays,
MaxBackups: fw.RollKeep,
LocalTime: fw.RollLocalTime,
Compress: *fw.RollCompress,
return &timberjack.Logger{
Filename: fw.Filename,
MaxSize: fw.RollSizeMB,
MaxAge: fw.RollKeepDays,
MaxBackups: fw.RollKeep,
LocalTime: fw.RollLocalTime,
Compress: *fw.RollCompress,
RotationInterval: fw.RollInterval,
RotateAtMinutes: fw.RollAtMinutes,
RotateAt: fw.RollAt,
BackupTimeFormat: fw.BackupTimeFormat,
}, nil
}

Expand Down Expand Up @@ -314,6 +332,53 @@ func (fw *FileWriter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
}
fw.RollKeepDays = int(math.Ceil(keepFor.Hours() / 24))

case "roll_interval":
var durationStr string
if !d.AllArgs(&durationStr) {
return d.ArgErr()
}
duration, err := time.ParseDuration(durationStr)
if err != nil {
return d.Errf("parsing roll_interval duration: %v", err)
}
fw.RollInterval = duration

case "roll_minutes":
var minutesArrayStr string
if !d.AllArgs(&minutesArrayStr) {
return d.ArgErr()
}
minutesStr := strings.Split(minutesArrayStr, ",")
minutes := make([]int, len(minutesStr))
for i := range minutesStr {
ms := strings.Trim(minutesStr[i], " ")
m, err := strconv.Atoi(ms)
if err != nil {
return d.Errf("parsing roll_minutes number: %v", err)
}
minutes[i] = m
}
fw.RollAtMinutes = minutes

case "roll_at":
var timeArrayStr string
if !d.AllArgs(&timeArrayStr) {
return d.ArgErr()
}
timeStr := strings.Split(timeArrayStr, ",")
times := make([]string, len(timeStr))
for i := range timeStr {
times[i] = strings.Trim(timeStr[i], " ")
}
fw.RollAt = times

case "backup_time_format":
var format string
if !d.AllArgs(&format) {
return d.ArgErr()
}
fw.BackupTimeFormat = format

default:
return d.Errf("unrecognized subdirective '%s'", d.Val())
}
Expand Down
Loading