GrepBoard/Manuals
47 manuals ·

Write a logrotate config and test it before using it

·logrotate 3.21.0 · Ubuntu 24.04 · systemd 255·6 steps

Write a logrotate config for an app log, preview it with -d, force a run with -f and a state file, and check the result. Covers copytruncate versus postrotate.

Run a new config from a scratch location before it goes into /etc/logrotate.d/. The output below was run on Ubuntu 24.04 with logrotate 3.21.0; only the paths were changed to /var/log/myapp and /etc/logrotate.d/myapp.

[1] Write the config for an app log. This file belongs at /etc/logrotate.d/myapp.

/etc/logrotate.d/myapp
/var/log/myapp/*.log {    daily    rotate 14    compress    delaycompress    missingok    notifempty    copytruncate}
OptionMeaning (per man logrotate)
dailyRotate once a day
rotate 14Keep 14 old logs; older ones are removed
compressCompress old logs with gzip
delaycompressPostpone compressing the just-rotated file to the next rotation
missingokIf the log file is missing, go on without an error
notifemptyDo not rotate an empty log
copytruncateCopy the file, then truncate the original in place instead of moving it

[2] Choose between copytruncate and postrotate. If the program can be told to reopen its log file, postrotate is safer; if not, use copytruncate. man logrotate warns that there is a very small time slice between copying the file and truncating it, so some logging data might be lost.

/etc/logrotate.d/myapp
/var/log/myapp/app.log {    daily    rotate 14    compress    delaycompress    missingok    notifempty    create 0640 root root    postrotate        systemctl reload myapp.service    endscript}

postrotate runs a script after the file is moved, so the script must make the program reopen its log. The systemctl reload line is an example. Here create makes the new log file; with copytruncate, create has no effect.

[3] Preview with -d. It changes nothing and only prints its decisions; -s names the state file (last rotation time per log). A new state file counts as "just rotated" and prints log does not need rotating. The run below used a state file holding a date two days old (renaming lines omitted).

console
# logrotate -d -s /tmp/myapp.state /etc/logrotate.d/myappreading config file /etc/logrotate.d/myappReading state from file: /tmp/myapp.stateHandling 1 logs rotating pattern: /var/log/myapp/*.log  after 1 days (14 rotations)empty log files are not rotated, old logs are removedconsidering log /var/log/myapp/app.log  Now: 2026-10-19 12:17  Last rotated at 2026-10-17 00:00  log needs rotatingconsidering log /var/log/myapp/empty.log  ...  log does not need rotating (log is empty)...copying /var/log/myapp/app.log to /var/log/myapp/app.log.1truncating /var/log/myapp/app.log

[4] Force a run with -f. It rotates regardless of schedule and updates the state file. File sizes (bytes) and names after the first rotation:

console
# logrotate -f -s /tmp/myapp.state /etc/logrotate.d/myapp# ls -l /var/log/myapp | tail -n +2 | awk '{print $5, $9}'0 app.log14 app.log.10 empty.log

app.log.1 is not compressed yet because of delaycompress. Append a line and force again to compress it.

console
# echo "line 3" >> /var/log/myapp/app.log# logrotate -f -s /tmp/myapp.state /etc/logrotate.d/myapp# ls -l /var/log/myapp | tail -n +2 | awk '{print $5, $9}'0 app.log7 app.log.131 app.log.2.gz0 empty.log

[5] Run the postrotate config the same way. The script runs only on a real rotation, such as one forced with -f. In the test, postrotate contained echo "reopen log" >> postrotate.out; afterwards postrotate.out held reopen log, and app.log was recreated with the permissions given to create (-rw-r-----).

[6] Find out who runs it once a day. On Ubuntu, logrotate.timer starts logrotate.service, which reads /etc/logrotate.conf.

console
$ systemctl list-timers logrotate.timer

The packaged unit files have OnCalendar=daily and Persistent=true (catch up on a missed run); the service is ExecStart=/usr/sbin/logrotate /etc/logrotate.conf.

#logrotate#logs