The ospsuite.utils package includes a set of utilities
to help with logging in R. The logging system takes avantage of 2 CRAN
packages: {logger}
and
{cli}
.
Get started
The function setLogFolder()
aims at initializing the
logging system. Its only argument is logFolder
, which is
NULL
by default.
When logFolder=NULL
, no log file is created, and all
logs are displayed in the console. When logFolder
is set to
a valid folder path, it will create a log.txt
file in that
folder, which will record all the log utilities defined below.
The example below sets a log folder within the sub-directory
test-logs
of the current working directory. Thus, the log
file will be located in test-logs/log.txt
dir.create("test-logs")
setLogFolder("test-logs")
💡 Note that you can use
setLogFolder()
without argument to stop logging.
The log utilities define 4 levels of logging below. Each log message is associated with a time stamp and the level of logging.
*1 Debug: for debugging purposes, its content are not displayed on the console
logDebug("Message for debugging purposes")
*2 Info: for general information, displayed in blue
logInfo("Message for general information")
#> ℹ Info [25/07/2025 - 09:29:59]: Message for general information
*3 Warning: for warnings, displayed in yellow
logWarning("Warning message")
#> ! Warning [25/07/2025 - 09:29:59]: Warning message
*4 Error: for errors, displayed in red
logError("Error message")
#> ✖ Error [25/07/2025 - 09:29:59]: Error message
Check the content of the log file test-logs/log.txt
to
see the logged messages.
readLines("test-logs/log.txt")
#> [1] "DEBUG [2025-07-25 09:29:59] Message for debugging purposes"
#> [2] "INFO [2025-07-25 09:29:59] Message for general information"
#> [3] "WARN [2025-07-25 09:29:59] Warning message"
#> [4] "ERROR [2025-07-25 09:29:59] Error message"
Taking advantage of glue and cli formatting
The logging utilities are designed to work with the {glue}
and {cli}
packages to format
messages.
Especially, the logInfo()
function includes a second
argument type
that allows you to specify the type of
message you want to log.
Here is a first example using glue/cli formatting:
logInfo("A logging example", type = "h1")
#>
#> ── A logging example ───────────────────────────────────────────────────────────
# tic() and toc() functions were implemented in ospsuite.utils
t0 <- tic()
logInfo("Some {.strong useful} information taking advantage of {.code logger}")
#> ℹ Info [25/07/2025 - 09:29:59]: Some useful information taking advantage of `logger`
Sys.sleep(2)
logInfo("First logging example done [{.field {toc(t0, 's')}}]", type = "success")
#> ✔ Info [25/07/2025 - 09:30:01]: First logging example done [2.0 s]
The content of the log has been appended to
test-logs/log.txt
removing most of the formatting displayed
on console.
readLines("test-logs/log.txt")
#> [1] "DEBUG [2025-07-25 09:29:59] Message for debugging purposes"
#> [2] "INFO [2025-07-25 09:29:59] Message for general information"
#> [3] "WARN [2025-07-25 09:29:59] Warning message"
#> [4] "ERROR [2025-07-25 09:29:59] Error message"
#> [5] "DEBUG [2025-07-25 09:29:59] A logging example"
#> [6] "INFO [2025-07-25 09:29:59] Some useful information taking advantage of `logger`"
#> [7] "SUCCESS [2025-07-25 09:30:01] First logging example done [2.0 s]"
The package ospsuite.utils also provides a wrapper to
store cli formatted messages: cliFormat()
.
💡 Note that, when an array of messages is provided to the log utilities, it is expected that the first element is usually the information, warning, or error message and subsequent elements are additional information that aims at helping refine or troubleshoot the first message. Thus, they are indicated through arrows in both console and logs.
Here is a second example using cliFormat()
, whose
warning will provide information about the class and length of the
variable x
:
myWarning <- function(x) {
cliFormat(
"Warning example about {.val x} !",
"{.val x} is of class {.code {class(x)}} and length {.strong {length(x)}}",
"The {length(x)} value{?s} of {.val x} {?is/are}: {.val {x}}"
)
}
x <- 10
logWarning(myWarning(x))
#> ! Warning [25/07/2025 - 09:30:01]: Warning example about "x" !
#> → "x" is of class `numeric` and length 1
#> → The 1 value of "x" is: 10
x <- letters[5:8]
logWarning(myWarning(x))
#> ! Warning [25/07/2025 - 09:30:01]: Warning example about "x" !
#> → "x" is of class `character` and length 4
#> → The 4 values of "x" are: "e", "f", "g", and "h"
The content of the log has also been appended to
test-logs/log.txt
removing most of the formatting displayed
on console.
readLines("test-logs/log.txt")
#> [1] "DEBUG [2025-07-25 09:29:59] Message for debugging purposes"
#> [2] "INFO [2025-07-25 09:29:59] Message for general information"
#> [3] "WARN [2025-07-25 09:29:59] Warning message"
#> [4] "ERROR [2025-07-25 09:29:59] Error message"
#> [5] "DEBUG [2025-07-25 09:29:59] A logging example"
#> [6] "INFO [2025-07-25 09:29:59] Some useful information taking advantage of `logger`"
#> [7] "SUCCESS [2025-07-25 09:30:01] First logging example done [2.0 s]"
#> [8] "WARN [2025-07-25 09:30:01] Warning example about \"x\" !"
#> [9] "\"x\" is of class `numeric` and length 1"
#> [10] "The 1 value of \"x\" is: 10"
#> [11] "WARN [2025-07-25 09:30:01] Warning example about \"x\" !"
#> [12] "\"x\" is of class `character` and length 4"
#> [13] "The 4 values of \"x\" are: \"e\", \"f\", \"g\", and \"h\""
Catching messages
The logging utilities also provide a way to catch information
provided by message()
, warning()
and
stop()
.
You can use the logCatch()
function to catch these
messages and log them accordingly.
logCatch({
logInfo("Testing {.fn logCatch}", type = "h1")
x <- c(
"This is a string",
"This is another string",
"This is a third string"
)
warning(cliFormat(
"Warning about {.val x} !",
"{.val x} is of class {.code {class(x)}} and length {.strong {length(x)}}",
"The {length(x)} value{?s} of {.val x} {?is/are}: {.val {x}}"
))
logInfo("Warning message was caught", type = "success")
})
#>
#> ── Testing `logCatch()` ────────────────────────────────────────────────────────
#> ! Warning [25/07/2025 - 09:30:02]: Warning about "x" !
#> → "x" is of class `character` and length 3
#> → The 3 values of "x" are: "This is a string", "This is another string", and "This is a third string"
#> ✔ Info [25/07/2025 - 09:30:02]: Warning message was caught
The content caught by the logCatch()
has also been
appended to test-logs/log.txt
removing most of the
formatting displayed on console.
readLines("test-logs/log.txt")
#> [1] "DEBUG [2025-07-25 09:29:59] Message for debugging purposes"
#> [2] "INFO [2025-07-25 09:29:59] Message for general information"
#> [3] "WARN [2025-07-25 09:29:59] Warning message"
#> [4] "ERROR [2025-07-25 09:29:59] Error message"
#> [5] "DEBUG [2025-07-25 09:29:59] A logging example"
#> [6] "INFO [2025-07-25 09:29:59] Some useful information taking advantage of `logger`"
#> [7] "SUCCESS [2025-07-25 09:30:01] First logging example done [2.0 s]"
#> [8] "WARN [2025-07-25 09:30:01] Warning example about \"x\" !"
#> [9] "\"x\" is of class `numeric` and length 1"
#> [10] "The 1 value of \"x\" is: 10"
#> [11] "WARN [2025-07-25 09:30:01] Warning example about \"x\" !"
#> [12] "\"x\" is of class `character` and length 4"
#> [13] "The 4 values of \"x\" are: \"e\", \"f\", \"g\", and \"h\""
#> [14] "DEBUG [2025-07-25 09:30:02] Testing `logCatch()`"
#> [15] "WARN [2025-07-25 09:30:02] Warning about \"x\" !"
#> [16] "\"x\" is of class `character` and length 3"
#> [17] "The 3 values of \"x\" are: \"This is a string\", \"This is another string\", and \"This is a third string\""
#> [18] "SUCCESS [2025-07-25 09:30:02] Warning message was caught"
Masking messages
You can use masking utilities to prevent the display of messages on
the console. The masking will use grepl()
to check for
patterns and will not display the message if a match is found.
For messages and warnings, the
masking can be set by the functions setInfoMasking()
and
setWarningMasking()
.
The example below will mask mask warning message that includes the
following patterns: not useful
and
another package
setWarningMasking("(not useful)*(another package)")
logCatch({
warning("This is a not useful message that is warned by another package")
warning("This is a useful message that I want displayed")
})
#> ! Warning [25/07/2025 - 09:30:02]: This is a useful message that I want displayed
The content caught by the logCatch()
includes the first
warning as debug message:
readLines("test-logs/log.txt")
#> [1] "DEBUG [2025-07-25 09:29:59] Message for debugging purposes"
#> [2] "INFO [2025-07-25 09:29:59] Message for general information"
#> [3] "WARN [2025-07-25 09:29:59] Warning message"
#> [4] "ERROR [2025-07-25 09:29:59] Error message"
#> [5] "DEBUG [2025-07-25 09:29:59] A logging example"
#> [6] "INFO [2025-07-25 09:29:59] Some useful information taking advantage of `logger`"
#> [7] "SUCCESS [2025-07-25 09:30:01] First logging example done [2.0 s]"
#> [8] "WARN [2025-07-25 09:30:01] Warning example about \"x\" !"
#> [9] "\"x\" is of class `numeric` and length 1"
#> [10] "The 1 value of \"x\" is: 10"
#> [11] "WARN [2025-07-25 09:30:01] Warning example about \"x\" !"
#> [12] "\"x\" is of class `character` and length 4"
#> [13] "The 4 values of \"x\" are: \"e\", \"f\", \"g\", and \"h\""
#> [14] "DEBUG [2025-07-25 09:30:02] Testing `logCatch()`"
#> [15] "WARN [2025-07-25 09:30:02] Warning about \"x\" !"
#> [16] "\"x\" is of class `character` and length 3"
#> [17] "The 3 values of \"x\" are: \"This is a string\", \"This is another string\", and \"This is a third string\""
#> [18] "SUCCESS [2025-07-25 09:30:02] Warning message was caught"
#> [19] "DEBUG [2025-07-25 09:30:02] This is a not useful message that is warned by another package"
#> [20] "WARN [2025-07-25 09:30:02] This is a useful message that I want displayed"
For errors, the masking is set by the function
setErrorMasking()
. The masking only affects the
error trace simplifying the final output.