Log messages are written to a file with basic log rotation: when
max number of lines or bytes is defined to be other than Inf,
then the log file is renamed with a .1 suffix and a new log file
is created. The renaming happens recursively (eg logfile.1
renamed to logfile.2) until the specified max_files, then the
oldest file (logfile.{max_files-1}) is deleted.
Arguments
- file
 path
- append
 boolean passed to
catdefining if the file should be overwritten with the most recent log message instead of appending- max_lines
 numeric specifying the maximum number of lines allowed in a file before rotating
- max_bytes
 numeric specifying the maximum number of bytes allowed in a file before rotating
- max_files
 integer specifying the maximum number of files to be used in rotation
See also
Other log_appenders:
appender_async(),
appender_console(),
appender_kinesis(),
appender_ntfy(),
appender_pushbullet(),
appender_slack(),
appender_stdout(),
appender_syslog(),
appender_tee(),
appender_telegram()
Examples
## ##########################################################################
## simple example logging to a file
t <- tempfile()
log_appender(appender_file(t))
for (i in 1:25) log_info(i)
readLines(t)
#>  [1] "INFO [2025-10-30 21:00:40] 1"  "INFO [2025-10-30 21:00:40] 2" 
#>  [3] "INFO [2025-10-30 21:00:40] 3"  "INFO [2025-10-30 21:00:40] 4" 
#>  [5] "INFO [2025-10-30 21:00:40] 5"  "INFO [2025-10-30 21:00:40] 6" 
#>  [7] "INFO [2025-10-30 21:00:40] 7"  "INFO [2025-10-30 21:00:40] 8" 
#>  [9] "INFO [2025-10-30 21:00:40] 9"  "INFO [2025-10-30 21:00:40] 10"
#> [11] "INFO [2025-10-30 21:00:40] 11" "INFO [2025-10-30 21:00:40] 12"
#> [13] "INFO [2025-10-30 21:00:40] 13" "INFO [2025-10-30 21:00:40] 14"
#> [15] "INFO [2025-10-30 21:00:40] 15" "INFO [2025-10-30 21:00:40] 16"
#> [17] "INFO [2025-10-30 21:00:40] 17" "INFO [2025-10-30 21:00:40] 18"
#> [19] "INFO [2025-10-30 21:00:40] 19" "INFO [2025-10-30 21:00:40] 20"
#> [21] "INFO [2025-10-30 21:00:40] 21" "INFO [2025-10-30 21:00:40] 22"
#> [23] "INFO [2025-10-30 21:00:40] 23" "INFO [2025-10-30 21:00:40] 24"
#> [25] "INFO [2025-10-30 21:00:40] 25"
## ##########################################################################
## more complex example of logging to file
## rotated after every 3rd line up to max 5 files
## create a folder storing the log files
t <- tempfile()
dir.create(t)
f <- file.path(t, "log")
## define the file logger with log rotation enabled
log_appender(appender_file(f, max_lines = 3, max_files = 5L))
## enable internal logging to see what's actually happening in the logrotate steps
log_threshold(TRACE, namespace = ".logger")
## log 25 messages
for (i in 1:25) log_info(i)
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 1' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 2' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 3' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] lines: 3, max_lines: 3, bytes: 87, max_bytes: Inf
#> TRACE [2025-10-30 21:00:40] lines >= max_lines || bytes >= max_bytes: TRUE
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log to /tmp/Rtmplq290W/file263b3f7422a4/log.1
#> TRACE [2025-10-30 21:00:40] killing the main file: /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 4' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 5' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 6' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] lines: 3, max_lines: 3, bytes: 87, max_bytes: Inf
#> TRACE [2025-10-30 21:00:40] lines >= max_lines || bytes >= max_bytes: TRUE
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.1 to /tmp/Rtmplq290W/file263b3f7422a4/log.2
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log to /tmp/Rtmplq290W/file263b3f7422a4/log.1
#> TRACE [2025-10-30 21:00:40] killing the main file: /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 7' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 8' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 9' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] lines: 3, max_lines: 3, bytes: 87, max_bytes: Inf
#> TRACE [2025-10-30 21:00:40] lines >= max_lines || bytes >= max_bytes: TRUE
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.2 to /tmp/Rtmplq290W/file263b3f7422a4/log.3
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.1 to /tmp/Rtmplq290W/file263b3f7422a4/log.2
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log to /tmp/Rtmplq290W/file263b3f7422a4/log.1
#> TRACE [2025-10-30 21:00:40] killing the main file: /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 10' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 11' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 12' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] lines: 3, max_lines: 3, bytes: 90, max_bytes: Inf
#> TRACE [2025-10-30 21:00:40] lines >= max_lines || bytes >= max_bytes: TRUE
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.3 to /tmp/Rtmplq290W/file263b3f7422a4/log.4
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.2 to /tmp/Rtmplq290W/file263b3f7422a4/log.3
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.1 to /tmp/Rtmplq290W/file263b3f7422a4/log.2
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log to /tmp/Rtmplq290W/file263b3f7422a4/log.1
#> TRACE [2025-10-30 21:00:40] killing the main file: /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 13' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 14' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 15' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] lines: 3, max_lines: 3, bytes: 90, max_bytes: Inf
#> TRACE [2025-10-30 21:00:40] lines >= max_lines || bytes >= max_bytes: TRUE
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.3 to /tmp/Rtmplq290W/file263b3f7422a4/log.4
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.2 to /tmp/Rtmplq290W/file263b3f7422a4/log.3
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.1 to /tmp/Rtmplq290W/file263b3f7422a4/log.2
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log to /tmp/Rtmplq290W/file263b3f7422a4/log.1
#> TRACE [2025-10-30 21:00:40] killing the main file: /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 16' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 17' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 18' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] lines: 3, max_lines: 3, bytes: 90, max_bytes: Inf
#> TRACE [2025-10-30 21:00:40] lines >= max_lines || bytes >= max_bytes: TRUE
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.3 to /tmp/Rtmplq290W/file263b3f7422a4/log.4
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.2 to /tmp/Rtmplq290W/file263b3f7422a4/log.3
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.1 to /tmp/Rtmplq290W/file263b3f7422a4/log.2
#> TRACE [2025-10-30 21:00:40] renaming /tmp/Rtmplq290W/file263b3f7422a4/log to /tmp/Rtmplq290W/file263b3f7422a4/log.1
#> TRACE [2025-10-30 21:00:40] killing the main file: /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:40] logging 'INFO [2025-10-30 21:00:40] 19' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:41] logging 'INFO [2025-10-30 21:00:40] 20' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:41] logging 'INFO [2025-10-30 21:00:41] 21' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:41] lines: 3, max_lines: 3, bytes: 90, max_bytes: Inf
#> TRACE [2025-10-30 21:00:41] lines >= max_lines || bytes >= max_bytes: TRUE
#> TRACE [2025-10-30 21:00:41] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.3 to /tmp/Rtmplq290W/file263b3f7422a4/log.4
#> TRACE [2025-10-30 21:00:41] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.2 to /tmp/Rtmplq290W/file263b3f7422a4/log.3
#> TRACE [2025-10-30 21:00:41] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.1 to /tmp/Rtmplq290W/file263b3f7422a4/log.2
#> TRACE [2025-10-30 21:00:41] renaming /tmp/Rtmplq290W/file263b3f7422a4/log to /tmp/Rtmplq290W/file263b3f7422a4/log.1
#> TRACE [2025-10-30 21:00:41] killing the main file: /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:41] logging 'INFO [2025-10-30 21:00:41] 22' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:41] logging 'INFO [2025-10-30 21:00:41] 23' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:41] logging 'INFO [2025-10-30 21:00:41] 24' to /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:41] lines: 3, max_lines: 3, bytes: 90, max_bytes: Inf
#> TRACE [2025-10-30 21:00:41] lines >= max_lines || bytes >= max_bytes: TRUE
#> TRACE [2025-10-30 21:00:41] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.3 to /tmp/Rtmplq290W/file263b3f7422a4/log.4
#> TRACE [2025-10-30 21:00:41] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.2 to /tmp/Rtmplq290W/file263b3f7422a4/log.3
#> TRACE [2025-10-30 21:00:41] renaming /tmp/Rtmplq290W/file263b3f7422a4/log.1 to /tmp/Rtmplq290W/file263b3f7422a4/log.2
#> TRACE [2025-10-30 21:00:41] renaming /tmp/Rtmplq290W/file263b3f7422a4/log to /tmp/Rtmplq290W/file263b3f7422a4/log.1
#> TRACE [2025-10-30 21:00:41] killing the main file: /tmp/Rtmplq290W/file263b3f7422a4/log
#> TRACE [2025-10-30 21:00:41] logging 'INFO [2025-10-30 21:00:41] 25' to /tmp/Rtmplq290W/file263b3f7422a4/log
## see what was logged
lapply(list.files(t, full.names = TRUE), function(t) {
  cat("\n##", t, "\n")
  cat(readLines(t), sep = "\n")
})
#> 
#> ## /tmp/Rtmplq290W/file263b3f7422a4/log 
#> INFO [2025-10-30 21:00:41] 25
#> 
#> ## /tmp/Rtmplq290W/file263b3f7422a4/log.1 
#> INFO [2025-10-30 21:00:41] 22
#> INFO [2025-10-30 21:00:41] 23
#> INFO [2025-10-30 21:00:41] 24
#> 
#> ## /tmp/Rtmplq290W/file263b3f7422a4/log.2 
#> INFO [2025-10-30 21:00:40] 19
#> INFO [2025-10-30 21:00:40] 20
#> INFO [2025-10-30 21:00:41] 21
#> 
#> ## /tmp/Rtmplq290W/file263b3f7422a4/log.3 
#> INFO [2025-10-30 21:00:40] 16
#> INFO [2025-10-30 21:00:40] 17
#> INFO [2025-10-30 21:00:40] 18
#> 
#> ## /tmp/Rtmplq290W/file263b3f7422a4/log.4 
#> INFO [2025-10-30 21:00:40] 13
#> INFO [2025-10-30 21:00:40] 14
#> INFO [2025-10-30 21:00:40] 15
#> [[1]]
#> NULL
#> 
#> [[2]]
#> NULL
#> 
#> [[3]]
#> NULL
#> 
#> [[4]]
#> NULL
#> 
#> [[5]]
#> NULL
#> 
