2

I have a function fun that often produces warnings and occasionally throws errors. I am trying to use tryCatch to log warnings and errors, as suggested in this answer. How can I simultaneously store the warnings and errors?

Here is a minimal setup:

# Function for warnings, errors.
fun <- function(i) {
    # Print warnings as they come in.
    options(warn = 1)

    # Issue warning.
    warning(paste("Warn.", i))

    # Stop.
    if(i == 3) { stop(paste("Err.", i)) }

    # Restore warning default behaviour.
    options(warn = 0)
}

Evaluating fun with tryCatch:

# Storage
warns = list()
errs = list()

# Try catch the function and log the warnings/ errors.
for (i in 1:4) {
    tryCatch(fun(i),
        warning = function(w) warns[[i]] <<- w,
        error = function(e) errs[[i]] <<- e
    )
}

However, the output shows that the error hasn't been stored.

warns
# [[1]]
# <simpleWarning in fun(i): Warn. 1>
# 
# [[2]]
# <simpleWarning in fun(i): Warn. 2>
# 
# [[3]]
# <simpleWarning in fun(i): Warn. 3>
# 
# [[4]]
# <simpleWarning in fun(i): Warn. 4>


errs
# list()
Mihai
  • 2,807
  • 4
  • 28
  • 53
  • I think `purrr::quietly` is exactly what you're looking for. https://purrr.tidyverse.org/reference/safely.html as it EXPLICITLY outputs errors and warnings as output. – Amit Kohli Aug 27 '19 at 08:02
  • @AmitKohli, thanks, useful to know about `quietly`, but I am curious about a base `R` solution! – Mihai Aug 27 '19 at 08:09
  • 1
    https://stackoverflow.com/questions/4948361/how-do-i-save-warnings-and-errors-as-output-from-a-function Helpful ? – Ronak Shah Aug 27 '19 at 08:19
  • @RonakShah, thanks, I am looking at it now. Will let you know if it helped! – Mihai Aug 27 '19 at 09:05
  • It helped, thank you for the mentioning that question! – Mihai Aug 27 '19 at 09:52

1 Answers1

2

Based on Ronak's helpful comment and the following question How do I save warnings and errors as output from a function?, the code can be simplified as follows:

# Storage.
warns = list()
errs = list()


# Example function.
fun <- function(i) {
    # Issue warning.
    warning(paste("Warn.", i))

    # Stop.
    if(i == 3) { stop(paste("Err.", i)) }
}


# Evaluate `fun`.
for (i in 1:4) {
    tryCatch(withCallingHandlers(
        expr = fun(i), 

        # Handle the warnings.
        warning = function(w) {
            warns <<- c(warns, list(w))
            invokeRestart("muffleWarning")
        }), 

        # Handle the errors.
        error = function(e) {
            errs <<- c(errs, list(e))
        }
    )
}

The output then looks like:

warns

# [[1]]
# <simpleWarning in fun(i): Warn. 1>
# 
# [[2]]
# <simpleWarning in fun(i): Warn. 2>
# 
# [[3]]
# <simpleWarning in fun(i): Warn. 3>
# 
# [[4]]
# <simpleWarning in fun(i): Warn. 4>


errs

# [[1]]
# <simpleError in fun(i): Err. 3>

More information and links are provided in the question linked above.

Mihai
  • 2,807
  • 4
  • 28
  • 53