Skip to content

[BUG] MaxBackups never deletes old monthly logs (cleanup glob derived from current month's basename) #1294

Open

Description

@BerziOnline

Summary

RotateOption.MaxBackups never deletes old monthly log files. The cleanup glob in RotateLog() is derived from the current log file's basename, so it can only ever match files belonging to the current month. Archived logs from previous months (zr_<year>-<month>.log) are never matched and accumulate indefinitely.

Observed on a production instance: 9 monthly log files, 1.8 GB total, none removed, with MaxBackups: 16 configured.

Affected code

src/mod/info/logger/rotate.go, in RotateLog():

baseName := filepath.Base(l.CurrentLogFile)
baseName = baseName[:len(baseName)-len(filepath.Ext(baseName))]
// ...
if l.RotateOption.MaxBackups > 0 {
    files, err := filepath.Glob(filepath.Join(backupDir, baseName+".*"))
    if err == nil && len(files) > l.RotateOption.MaxBackups {
        // delete oldest
    }
}

baseName comes from l.CurrentLogFile. Per src/mod/info/logger/logger.go:

func (l *Logger) getLogFilepath() string {
	year, month, _ := time.Now().Date()
	return filepath.Join(l.LogFolder, l.Prefix+"_"+strconv.Itoa(year)+"-"+strconv.Itoa(int(month))+".log")
}

So in September 2026 baseName is zr_2026-9, and the glob is:

/opt/zoraxy/log/zr_2026-9.*

That pattern cannot match zr_2026-8.log, zr_2026-7.log, etc. The month is part of the basename itself, so each month's cleanup only ever sees its own files. MaxBackups is effectively a no-op for the monthly rollover files produced by ArchiveLog().

Second contributing factor

LogNeedRotate() returns early unless info.Size() >= l.RotateOption.MaxSize. A config carrying "maxSize": "0" (the value shipped in conf/log_conf.json on this instance) is parsed as 0, and while size >= 0 is technically always true, the whole path is gated behind RotateOption.Enabled, which defaults to false. Combined, an operator who never touches the logging settings gets no rotation and no retention at all — which is easy to miss because the monthly rollover in ArchiveLog() does keep producing new files and looks like rotation is working.

Steps to reproduce

  1. Run Zoraxy across several month boundaries so ArchiveLog() creates zr_<year>-<month>.log files.
  2. Set RotateOption.Enabled = true with any MaxBackups smaller than the number of existing monthly files.
  3. Trigger rotation (hourly ticker or POST /api/log/rotate/trigger).

Expected: oldest monthly logs beyond MaxBackups are removed.
Actual: nothing is removed; only files matching the current month's prefix are ever considered.

Environment

  • Zoraxy 3.3.4 (also present in main at time of writing)
  • Debian 13, amd64, systemd service
  • conf/log_conf.json: {"enabled": false, "maxSize": "0", "maxBackups": 16, "compress": true}

Suggested fix

Derive the cleanup pattern from the logger's Prefix rather than from the current file's basename, and exclude the file currently being written:

pattern := filepath.Join(backupDir, l.Prefix+"_*.log*")
files, err := filepath.Glob(pattern)
// filter out l.CurrentLogFile before applying MaxBackups

Sorting lexicographically also mis-orders months once the year has more than nine (zr_2026-10 sorts before zr_2026-9), so ordering by modification time — or zero-padding the month in getLogFilepath() — would be worth addressing in the same change. Note that zero-padding alone would change existing filenames, so the glob should tolerate both forms during a transition.

A time-based retention option (MaxAge in days) alongside MaxBackups would also fit the monthly-file model better than a pure count, since one file equals one month.

Workaround for other operators

Until this is fixed, an external timer that compresses and prunes zr_*.log files works, as long as it never touches the file for the current month (Zoraxy holds it open, and log consumers such as CrowdSec tail it via a wildcard).

Activity

  1. tobychui commented on Sep 17, 2026

    @tobychui
    Owner

    Will look into it later this weekend.

    Btw since you already dig into the code base, you got interest to be our log system maintainer? I have been looking for someone to help with maintaining the log module, some additional help would be greatly appreciated ✨

  2. BerziOnline commented on Sep 17, 2026

    @BerziOnline
    ContributorAuthor

    Will look into it later this weekend.

    Thank you very much!

    Btw since you already dig into the code base, you got interest to be our log system maintainer? I have been looking for someone to help with maintaining the log module, some additional help would be greatly appreciated ✨

    Thank you very much, but to be honest I have not a very well coding background, being more network technician O:-)

  3. added a commit that references this issue on Sep 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions