# Getting Started

`loggit2` is an easy-to-use, yet powerful, `ndjson` logger. It is very fast, has zero external dependencies, and can be as straightforward or as integral as you want to make it.

## Preparation

No preparations are needed to use `loggit2`. However, it is recommended to explicitly set a log file using `loggit2::set_logfile("path/to/your/file")`, as `loggit2` defaults to creating a file in your temporary directory.1

In order to use the full potential of `loggit2`, it is advisable to take a look at the further configurations after reading this vignette.

## Logging

There are three ways to populate the log in `loggit2`. First, through wrapper functions of the base `R` condition handler, second, via the `loggit()` log function, and third, by logging (external) expressions using `with_loggit()`.

Each function of these three methods has the parameter `echo`, which determines whether the log entries should also be echoed to `stdout`.

### Condition Log Handling

`loggit2` provides a set of wrappings for base R’s `message()`, `warning()`, `stop()` and `stopifnot()` functions that maintain identical functionality2, except the additional logging. Thus, it is sufficient to import the `loggit2` namespace, for example by using `library("loggit2")`, or by prefixing `loggit2::` at the desired locations.

    base::message("This is another message")
    #> This is another message
    loggit2::message("This is a message")
    #> {"timestamp": "2025-06-01T20:18:50+0200", "log_lvl": "INFO", "log_msg": "This is a message\n"}
    #> This is a message

    base::warning("This is another warning")
    #> Warning: This is another warning
    loggit2::warning("This is a warning")
    #> {"timestamp": "2025-06-01T20:18:50+0200", "log_lvl": "WARN", "log_msg": "This is a warning"}
    #> Warning: This is a warning

    base::stop("This is another error")
    #> Error: This is another error
    loggit2::stop("This is an error")
    #> {"timestamp": "2025-06-01T20:18:50+0200", "log_lvl": "ERROR", "log_msg": "This is an error"}
    #> Error: This is an error

    base::stopifnot("This is another condition" = FALSE)
    #> Error: This is another condition
    loggit2::stopifnot("This is another condition" = FALSE)
    #> {"timestamp": "2025-06-01T20:18:50+0200", "log_lvl": "ERROR", "log_msg": "This is another condition"}
    #> Error: This is another condition

Besides the `echo` parameter, the functions have an additional parameter `.loggit`, which allows to deactivate the logging such that the function behaves exactly like the base `R` equivalents.

    loggit2::warning("This is a alternative warning", echo = FALSE)
    #> Warning: This is a alternative warning

    loggit2::warning("This is not part of the log", .loggit = FALSE)
    #> Warning: This is not part of the log

Click here to see the generated log

    #>                   timestamp log_lvl                                                                  log_msg
    #> 1  2025-06-01T20:18:49+0200    INFO              This message will be logged, since the log level is INFO.\n
    #> 2  2025-06-01T20:18:49+0200   DEBUG            This message will be logged because the log level is ignored.
    #> 3  2025-06-01T20:18:49+0200    INFO                     This message will be logged, since .loggit = TRUE.\n
    #> 4  2025-06-01T20:18:49+0200   ERROR This error message will be logged because the log level is set to ERROR.
    #> 5  2025-06-01T20:18:49+0200    INFO     This message will be logged because the log level is set to DEBUG.\n
    #> 6  2025-06-01T20:18:49+0200    INFO This message will not be logged, but it will be output to the console.\n
    #> 7  2025-06-01T20:18:49+0200    INFO                 This message will be logged and output to the console.\n
    #> 8  2025-06-01T20:18:49+0200    INFO                 This message will be logged and output to the console.\n
    #> 9  2025-06-01T20:18:49+0200    INFO                This message will be logged, but it will not be echoed.\n
    #> 10 2025-06-01T20:18:49+0200    INFO This message will be logged, but it will not be output to the console.\n
    #> 11                 20:18:49    INFO   This message will be logged with a timestamp in the format HH:MM:SS.\n
    #> 12 2025-06-01T20:18:50+0200    INFO                                                      This is a message\n
    #> 13 2025-06-01T20:18:50+0200    WARN                                                        This is a warning
    #> 14 2025-06-01T20:18:50+0200   ERROR                                                         This is an error
    #> 15 2025-06-01T20:18:50+0200   ERROR                                                This is another condition
    #> 16 2025-06-01T20:18:50+0200    WARN                                            This is a alternative warning

### Explicit Log Function

`loggit2` allows direct access to the core logging function `loggit()`. This enables setting the log level directly during the call and creating arbitrary fields in the log.

This function does not trigger any conditions; it only populates the log.

    loggit2::loggit("INFO", "This is a message", ID = 1L, boole = TRUE)
    #> {"timestamp": "2025-06-01T20:18:50+0200", "log_lvl": "INFO", "log_msg": "This is a message", "ID": "1", "boole": "TRUE"}

    loggit2::loggit("WARN", "This is a alternative warning", echo = FALSE)

    loggit2::loggit("DEBUG", "This is a message", Why = "Because", echo = FALSE)

To allow log levels other than “DEBUG”, “INFO”, “WARN” or “ERROR” the `custom_log_lvl` parameter must be set.

    loggit2::loggit("CRITICAL", "Critical error")
    #> Error in loggit2::loggit("CRITICAL", "Critical error"): Nonstandard log_lvl ('CRITICAL').
    #> Should be one of DEBUG, INFO, WARN, or ERROR. Please check if you made a typo.
    #> If you insist on passing a custom level, please set 'custom_log_lvl = TRUE' in the call to 'loggit()'.

    loggit2::loggit("CRITICAL", "Critical error 2", custom_log_lvl = TRUE)
    #> {"timestamp": "2025-06-01T20:18:50+0200", "log_lvl": "CRITICAL", "log_msg": "Critical error 2"}

Click here to see the generated log

    #>                  timestamp  log_lvl                       log_msg   ID boole     Why
    #> 1 2025-06-01T20:18:50+0200     INFO             This is a message    1  TRUE    <NA>
    #> 2 2025-06-01T20:18:50+0200     WARN This is a alternative warning <NA>  <NA>    <NA>
    #> 3 2025-06-01T20:18:50+0200    DEBUG             This is a message <NA>  <NA> Because
    #> 4 2025-06-01T20:18:50+0200 CRITICAL              Critical error 2 <NA>  <NA>    <NA>

### Log Expressions

One will repeatedly encounter situations where conditions need to be logged from code without wanting to or being able to modify it (e.g., when dealing with functions from external packages). In this case, `with_loggit()` comes into play. This function allows logging conditions from arbitrary expressions without restricting functionality3 or needing to modify the code.

    fun_a <- function(x) {
      base::warning("This is a warning")
      base::message("This is a message")
      base::stopifnot("This is true" = 3L == 1L + 2L, "This is not TRUE" = FALSE)
    }

    fun_b <- function(x) {
      base::warning("This is a second warning")
      5L + 5L
    }

    x <- loggit2::with_loggit(fun_b())
    #> {"timestamp": "2025-06-01T20:18:50+0200", "log_lvl": "WARN", "log_msg": "This is a second warning"}
    #> Warning in fun_b(): This is a second warning
    print(x)
    #> [1] 10

    loggit2::with_loggit({
      x <- fun_b()
      fun_a()
    }, echo = FALSE)
    #> Warning in fun_b(): This is a second warning
    #> Warning in fun_a(): This is a warning
    #> This is a message
    #> Error in fun_a(): This is not TRUE

Additionally, `with_loggit()` allows alternative settings (logfile, echo, etc.) to be used for a specific section of code.

Click here to see the generated log

    #>                  timestamp log_lvl                  log_msg
    #> 1 2025-06-01T20:18:50+0200    WARN This is a second warning
    #> 2 2025-06-01T20:18:50+0200    WARN This is a second warning
    #> 3 2025-06-01T20:18:50+0200    WARN        This is a warning
    #> 4 2025-06-01T20:18:50+0200    INFO      This is a message\n
    #> 5 2025-06-01T20:18:50+0200   ERROR         This is not TRUE

## Post-Processing

A log is of little use without the ability to access and modify it. Here are a few possibilities.

### Accessing the Log

As seen above, the log can be queried as a `data.frame` using `read_logs()`.

    loggit2::read_logs()
    #>                  timestamp log_lvl                  log_msg
    #> 1 2025-06-01T20:18:50+0200    WARN This is a second warning
    #> 2 2025-06-01T20:18:50+0200    WARN This is a second warning
    #> 3 2025-06-01T20:18:50+0200    WARN        This is a warning
    #> 4 2025-06-01T20:18:50+0200    INFO      This is a message\n
    #> 5 2025-06-01T20:18:50+0200   ERROR         This is not TRUE

Alternatively, the log can also be saved as a CSV file using `convert_to_csv()`.

    loggit2::convert_to_csv("path/to/your/file.csv")

### Rotating the Log

To maintain a clear log even in long-running sessions (e.g., in a Shiny app hosted on a server), the log can be restricted to the last `n` entries using `rotate_logs(n)`.

    loggit2::rotate_logs(2L)

Click here to see the generated log

    #>                  timestamp log_lvl             log_msg
    #> 1 2025-06-01T20:18:50+0200    INFO This is a message\n
    #> 2 2025-06-01T20:18:50+0200   ERROR    This is not TRUE

    loggit2::rotate_logs(0L)

Click here to see the generated log

    #> [1] timestamp log_lvl   log_msg
    #> <0 Zeilen> (oder row.names mit Länge 0)

1. This is done to CRAN Repository Policy:

   > Packages should not write in the user’s home filespace (including clipboards), nor anywhere else on the file system apart from the R session’s temporary directory `[...]`.

   ↩︎

2. This means in particular that `tryCatch` and similar functions can be used as usual.↩︎

3. Just like with the direct use of the wrappers for condition handlers, `tryCatch` and similar mechanisms can be used as usual.↩︎