rotor provides a cross platform R reimagination of logrotate. It is a companion package to the logging package lgr. In contrast to logrotate, rotor relies solely on information encoded in a suffixes of file names for conditionally creating backups (i.e. a timestamp or index). It therefore also works with backups created by other tools, as long as the filename has a format that rotor can understand.
rotate_time() move a file and insert a suffix (either an integer or a timestamp) into the filename. In addition, they create an empty file in place of the original one. This is useful for log rotation.
backup_time() do the same but keep the original file.
rotor also includes utility functions for finding and examining the backups of a file:
oldest_backup(). See the function reference for details.
You can install the released version of rotor from CRAN with:
And the development version from GitHub with:
First we create a temporary directory for the files created by the code examples
backup() makes a copy of a file and inserts an index between the filename and the file extension. The file with the index
1 is always the most recently made backup.
rotate() also backs up a file, but replaces the original file with an empty one.
rotate(tf) list_backups(tf) #>  "/tmp/RtmpTB9vY3/rotor/mylogfile.1.log" #>  "/tmp/RtmpTB9vY3/rotor/mylogfile.2.log.zip" #>  "/tmp/RtmpTB9vY3/rotor/mylogfile.3.log" # the original file is now empty readLines(tf) #> character(0) # its content was moved to the first backup readLines(list_backups(tf)[]) #>  "An important message" # we can now safely write to the original file writeLines("another important message", tf)
max_backups parameter limits the maximum number of backups rotor will keep of a file. Notice how the zipped backup we created above moves to index 4 as we create two new backups.
We can also use
prune_backups() to delete old backups. Other than ensuring that no new backups is created, it works identically to using
backup() with the
max_backups parameter. By setting it to
0, we delete all backups.
rotor can also create timestamped backups.
backup_date() creates uses a Date (
backup_time() uses a full datetime-stamp by default (
yyyy-mm-dd--hh-mm-ss). The format of the timestamp can be modified with a subset of the formatting tokens understood by
strftime() (within certain restrictions). Backups created with both functions are compatible with each other (but not with those created with
# be default backup_date() only makes a backup if the last backups is younger # than 1 day, so we set `age` to -1 for this example backup_date(tf, age = -1) backup_date(tf, format = "%Y-%m", age = -1) backup_time(tf) backup_time(tf, format = "%Y-%m-%d_%H-%M-%S") # Python logging backup_time(tf, format = "%Y%m%dT%H%M%S") # ISO 8601 compatible backup_info(tf) #> path name #> 1 /tmp/RtmpTB9vY3/rotor/mylogfile.2020-01-02_10-05-52.log mylogfile #> 2 /tmp/RtmpTB9vY3/rotor/mylogfile.2020-01-02--10-05-52.log mylogfile #> 5 /tmp/RtmpTB9vY3/rotor/mylogfile.20200102T100552.log mylogfile #> 3 /tmp/RtmpTB9vY3/rotor/mylogfile.2020-01-02.log mylogfile #> 4 /tmp/RtmpTB9vY3/rotor/mylogfile.2020-01.log mylogfile #> sfx ext size isdir mode mtime #> 1 2020-01-02_10-05-52 log 26 FALSE 664 2020-01-02 10:05:52 #> 2 2020-01-02--10-05-52 log 26 FALSE 664 2020-01-02 10:05:52 #> 5 20200102T100552 log 26 FALSE 664 2020-01-02 10:05:52 #> 3 2020-01-02 log 26 FALSE 664 2020-01-02 10:05:52 #> 4 2020-01 log 26 FALSE 664 2020-01-02 10:05:52 #> ctime atime uid gid uname grname #> 1 2020-01-02 10:05:52 2020-01-02 10:05:52 1032 1032 fleck fleck #> 2 2020-01-02 10:05:52 2020-01-02 10:05:52 1032 1032 fleck fleck #> 5 2020-01-02 10:05:52 2020-01-02 10:05:52 1032 1032 fleck fleck #> 3 2020-01-02 10:05:52 2020-01-02 10:05:52 1032 1032 fleck fleck #> 4 2020-01-02 10:05:52 2020-01-02 10:05:52 1032 1032 fleck fleck #> timestamp #> 1 2020-01-02 10:05:52 #> 2 2020-01-02 10:05:52 #> 5 2020-01-02 10:05:52 #> 3 2020-01-02 00:00:00 #> 4 2020-01-01 00:00:00
If we examine the “timestamp” column in the example above, we see that missing date information is always interpreted as the start of the period; i.e. so
"2019-01" is equivalent to
"2019-01-01--00--00--00" for all intents and purposes.
Besides passing a total number of backups to keep,
max_backups can also be a period or a date / datetime for timestamped backups.
rotor’s dependencies are intentionally kept slim. It only comes with two non-base dependencies:
rotate_time()to deal with calendar periods (such as weeks or months).
Both packages have no transitive dependencies (i.e they do not depend on anything outside of base R)