--- title: "Introduction to luzlogr" author: "Ben Bond-Lamberty" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{intro-luzlogr} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- This vignette describes how to use the **luzlogr** package, which provides flexible but lightweight logging facilities for R scripts. ## Installing To install this package, use R's `install.packages()` function or the "Packages" pane in RStudio. To install the latest, developmental version of this package from GitHub: 1. Make sure you have the `devtools` package installed from CRAN and loaded. 2. `install_github("bpbond/luzlogr")` ## Basics Three functions - `openlog()`, `printlog()`, `closelog()` - provide logging of script output. They're simple to use: ```{r} library(luzlogr) openlog("test.log") printlog("message") closelog() ``` The resulting log file `test.log` looks like this (not including the initial `##` characters): ```{r, echo=FALSE} lg <- readLines("test.log") invisible(file.remove("test.log")) for(i in seq_along(lg)) cat(lg[i], "\n") ``` By default individual lines are prefixed with a timestamp, end with a carriage return, and the entire log starts with an open message and ends with a close one. Any printable object can be written to a log. For example: ```{r} openlog("test.log") printlog("message", 1, 2) printlog(head(cars)) closelog(sessionInfo = FALSE) ``` (Notice in this case we've told `closelog()` not to append `sessionInfo()` output, as it does by default.) ```{r, echo=FALSE} lg <- readLines("test.log") invisible(file.remove("test.log")) for(i in seq_along(lg)) cat(lg[i], "\n") ``` ## More involved examples By design, `luzlogr` is intended to be simple and easy to use. Nonetheless, it does provide additional features, including: * priority levels for logs and messages * flagging messages * capturing all script output * logging to a text file or arbitrary [connection](https://stat.ethz.ch/R-manual/R-devel/library/base/html/connections.html) * switching logs ### Priority levels In many circumstances, we want messages to have different priorities or *levels* associated with them. Each logfiles has a minimum priority level, set when it's opened, making it easy to produce logs with varying levels of detail--for example, under development versus release conditions. By default, **luzlogr** logs have a minimum levels of `-Inf`: in other words, they'll accept every single message sent to them via `printlog()`, which produces messages with a default level of zero. We can change the log's level, however, and this will then affect which messages appear in the log. ```{r} openlog("test.log", loglevel = 0) printlog("This message will appear", level = 0) printlog("So will this (level 0 by default)") printlog("This will not", level = -1) closelog(sessionInfo = FALSE) ``` produces ```{r, echo=FALSE} lg <- readLines("test.log") invisible(file.remove("test.log")) for(i in seq_along(lg)) cat(lg[i], "\n") ``` Notice that the third message didn't get logged. If we change the `loglevel` parameter in `openlog()` to -1 or lower, however, all these messages will appear. ### Flagging messages Another way to differentiate messages is by *flagging* them. Note that in all the above examples, when the log is closed, a `flags = 0` message is printed. But we can change that: ```{r} openlog("test.log") printlog("A normal message") printlog("A flagged message!", flag = TRUE) flaglog("Another") closelog(sessionInfo = FALSE) ``` ```{r, echo=FALSE} lg <- readLines("test.log") invisible(file.remove("test.log")) for(i in seq_along(lg)) cat(lg[i], "\n") ``` ### Capturing all output So far, only messages sent via `printlog()` appear in the log. We might, however, want to capture *everything*^[Almost. Messages, warnings, and errors will not appear; but see `?sink` and its `type = "message"` parameter.] produced by a script. To do this, use the `sink = TRUE` option of `openlog()`. ### Errors and logs If an error occurs in your script, any log files will by default remain open. If using a single log file, it's easy to put a statement such as `suppressWarnings(closelog())` at the start of your script. Alternatively, you can tell **luzlogr** to close all open logs if an error occurs: ```{r, eval=FALSE} options(luzlogr.close_on_error = TRUE) ``` ### Logging to a connection Logs can also be sent to any R [connection](https://stat.ethz.ch/R-manual/R-devel/library/base/html/connections.html): a pipe, compressed file, URL, etc. ```{r} con <- gzfile("test.log.gz") openlog(con) printlog("Sending to a compressed logfile") closelog(sessionInfo = FALSE) ``` ```{r, echo=FALSE} invisible(file.remove("test.log.gz")) ``` Note that **luzlogr** won't close a connection that was already open at the time of the `openlog()` call. ### Switching logs If you're logging to log A and open log B (without closing A), subsequent `printlog()` messages will go to B. When you close B, logging switches back to A (i.e., there's a stack of logs that gets pushed/popped when necessary). If you need to append to an existing log, use `append = TRUE` when calling `openlog()`. By default, existing logfiles are erased upon opening. This concludes the **Introduction to luzlogr** vignette.