How to rotate an application's logs¶
An application writes its own log file, /var/log/myapp/myapp.log, which grows until it fills the disk.
This guide adds a logrotate rule that rotates the file every day, compresses the old copies and deletes them after two weeks, tests the rule, and makes sure logrotate runs regularly.
Replace myapp and the path with your application's.
Before you begin¶
- You need a shell with
sudoon the machine. - Find out whether the application can be told to reopen its log file, for example with a signal (often
SIGHUPorSIGUSR1) or a reload command. The rule below works for any application; Reopen the file instead of copying it shows the better variant for applications that can. - Check what already rotates the file:
grep -r myapp /etc/logrotate.d/should print nothing, since two rules for one file makelogrotatereport an error.
Steps¶
-
Make sure
logrotateis installed and runs every day.Standard Debian and Ubuntu installations include
logrotate; only the Debian 13 cloud image doesn't, andapt-getleaves an existing installation as it is. Installing the package also enables a systemd timer that runs it daily:logrotateis installed by default and run daily by a systemd timer:Install
logrotate, and start its daily timer now (the package links the timer intotimers.target, so otherwise it would only start at the next boot):Install
logrotate, and a cron daemon to run it.app-admin/logrotateinstalls a daily job,/etc/cron.daily/logrotate, whichcronieruns throughanacron, so it also runs after the machine was switched off at the scheduled time:sudo emerge --getbinpkg --noreplace app-admin/logrotate sys-process/cronie sudo rc-update add cronie default sudo rc-service cronie startThis needs a synchronised ebuild repository (
emerge --sync). If another cron daemon is already running, keep it instead ofcronie: any that runs/etc/cron.dailywill do.On the systemd families, the
NEXTcolumn ofsystemctl list-timersshows whenlogrotateruns next. -
Create the rule,
/etc/logrotate.d/myapp:/var/log/myapp/*.log { daily rotate 14 missingok notifempty compress delaycompress dateext copytruncate }Directive Effect dailyRotate once a day rotate 14Keep 14 old copies, and delete older ones missingokDon't report an error if no file matches notifemptyDon't rotate a file that is empty compressCompress old copies with gzipdelaycompressLeave the newest old copy uncompressed until the next rotation, in case the application is still writing to it dateextName old copies after the date, such as myapp.log-20261107, instead of numbering themcopytruncateCopy the file, then empty the original in place, so the application keeps writing to the same open file The pattern
*.logmatches every file ending in.login the directory, but not the rotated copies. Don't use*on its own: it would match the old copies too, and rotate them again./etc/logrotate.confsets global defaults, such asweeklyandrotate 4, and reads the files in/etc/logrotate.d/. The rule repeats every setting it needs, so it behaves the same on every distribution and when you test it on its own. See logrotate directives for other directives, such asmaxsizeto rotate early when the file grows fast. -
Test the rule in debug mode, which shows what
logrotatewould do without changing anything:$ sudo logrotate -d /etc/logrotate.d/myapp warning: logrotate in debug mode does nothing except printing debug messages! Consider using verbose mode (-v) instead if this is not what you want. reading config file /etc/logrotate.d/myapp Reading state from file: /var/lib/logrotate/status Allocating hash table for state file, size 64 entries Handling 1 logs rotating pattern: /var/log/myapp/*.log after 1 days empty log files are not rotated, (14 rotations), old logs are removed considering log /var/log/myapp/myapp.log Creating new state Now: 2026-11-07 14:10 Last rotated at 2026-11-07 14:00 log does not need rotating (log has already been rotated)Check that the
considering loglines list the files you expect, and that there are noerror:orwarning:lines other than the first. A mistyped directive produces only a warning, such aswarning: /etc/logrotate.d/myapp:2 unknown option 'dialy' -- ignoring line, and the rest of the rule then runs without it. The first time it sees a file,logrotateonly records it in its state file, as if it had just been rotated, solog does not need rotatingis normal here. The path of the state file differs between distributions. -
Force a rotation once, to see the result without waiting a day:
$ sudo logrotate -f /etc/logrotate.d/myapp $ ls -l /var/log/myapp/ total 20 -rw-r--r-- 1 root root 0 Nov 7 14:11 myapp.log -rw-r--r-- 1 root root 21392 Nov 7 14:11 myapp.log-20261107myapp.logis now empty and the application keeps writing to it; the previous content is inmyapp.log-20261107. Because ofdelaycompress, that copy is compressed at the next rotation.
Reopen the file instead of copying it¶
copytruncate has a drawback: anything the application writes between the copy and the truncation is lost, and the copy costs time and space for a large file.
If the application can reopen its log file, let logrotate rename the file, create a new one, and then tell the application to switch to it.
Replace copytruncate with create and a postrotate script, for example for a systemd service whose reload reopens its logs:
/var/log/myapp/*.log {
daily
rotate 14
missingok
notifempty
compress
delaycompress
dateext
create 0640 myapp myapp
sharedscripts
postrotate
systemctl reload myapp.service >/dev/null 2>&1 || true
endscript
}
create 0640 myapp myapp creates the new, empty file with that mode, owner and group; use the owner the application runs as.
sharedscripts runs the script once for all the files that match, rather than once per file.
On Gentoo with OpenRC, use rc-service myapp reload in the script, if the service's init script supports reload.
Verify¶
Check that the rule rotated the file and that logrotate is scheduled to run:
The next day, ls /var/log/myapp/ shows a new dated copy, and the previous one compressed with a .gz suffix.
Troubleshooting¶
error: skipping "/var/log/myapp/myapp.log" because parent directory has insecure permissions- The directory can be written by a group or by everyone, so a non-root user could trick
logrotate, which runs as root, into overwriting other files. Addsu <USER> <GROUP>to the rule, naming the user and group that own the directory, so thatlogrotaterotates the files as that user. logrotatereports a duplicate log entry- Two rules match the same file, for example one shipped by the application's package. Keep one of them.
destination /var/log/myapp/myapp.log-20261107 already exists, skipping rotation- With
dateext, a file can be rotated only once a day, because the copy's name contains the date. This happens when you force a second rotation on the same day; it doesn't affect the daily run. - Logs under
/etcor/usraren't rotated by the daily run, althoughlogrotate -fworks - On the systemd families,
logrotate.serviceruns withProtectSystem=full, which makes/usr,/boot,/efiand/etcread-only for it; other locations, such as/var/log,/srvor/opt, are unaffected. Move the logs out of/etcand/usr. On the RHEL family, SELinux also limitslogrotateto files with log labels; check withls -Z, and look for denials withsudo ausearch -m avc -c logrotate.
Related¶
- Reference: logrotate directives
- Explanation: Linux logging architecture
- How-to: How to search the logs for a problem, How to keep logs across reboots, How to forward logs to a remote syslog server