3

I have a function fun that relies on an external function external (i.e., from some package). How can I collect all the warnings that come out of external in a character vector?

This is a minimal setup:

# External function from another package.
external <- function() {
    warning("warning from external...")
}


# Function meant to capture the warnings.
fun <- function() {
    # Create variable to store the warnings.
    warns <- vector("character")

    # Create connection for the sink.
    connection <- textConnection("warns", "wr", local = TRUE)

    # Start collecting.
    sink(connection, type = "message")

    # Call external function and produce a warning.
    external()

    # Reset the sink.
    sink(type = "message")

    # Close the connection.
    close(connection)

    return(warns)
}

The output, however looks like this:

x <- fun()
# Warning message:
# In external() : warning from external...

print(x)
# character(0)

I am not interested in suppressWarnings, but rather to log these warnings. When I use sink outside of a function it seems to work, just as indicated in this answer.

Mihai
  • 2,807
  • 4
  • 28
  • 53
  • Do you know `warnings` are already logged? – James Aug 26 '19 at 12:49
  • You mean in the `last.warning` created by R? – Mihai Aug 26 '19 at 12:51
  • 1
    Yes, but you might also want to look at the option `warning.expression` to override the behaviour on a warning - i.e. log rather than print. – James Aug 26 '19 at 12:55
  • @James, can you expand a little bit? I think this approach is very interesting! – Mihai Aug 26 '19 at 12:58
  • I just found out that *'If `warn` is zero (the default) warnings are stored until the top–level function returns.'* Setting it to `1` before the sink allowed for the warnings to be captured by the sink. But I am very curious the `warning.expression` path. – Mihai Aug 26 '19 at 13:00
  • 1
    It might not be possible unfortunately, there's a discussion here: https://stackoverflow.com/questions/48071718/warning-expression-prevents-last-warning-from-update – James Aug 26 '19 at 13:10
  • Reading it right now. I think I get the idea. Thanks for the insight! – Mihai Aug 26 '19 at 13:12

3 Answers3

2

You can use tryCatch for this:

fun <- function() {
  tryCatch(external(), warning = function(my_warn) my_warn$message)
}

x <-fun()

x
# [1] "warning from external..."
thothal
  • 16,690
  • 3
  • 36
  • 71
  • I was completely oblivious to the `warning` argument of `tryCatch`. Good one! – Mihai Aug 26 '19 at 13:02
  • Can you please take a look at [this question](https://stackoverflow.com/q/57669971/5252007) inspired by your answer? Thanks! – Mihai Aug 27 '19 at 08:02
1

You can try evaluate() function from evaluate package, if you want to store warnings in a character vector:

external <- function() {
  warning("warning from external...")
}

# Function meant to capture the warnings.
fun <- function() {
   #some operation
   x=1+2;
   warnings_ls = evaluate::evaluate(external())
   return(list(value=x,warn=warnings_ls))
}

x <- fun()

> a$warn[[1]]$src
[1] "warning from external..."

> a$value
[1] 3
Rushabh Patel
  • 2,672
  • 13
  • 34
1

Supplementing the answers above, the warn option (see ?options) says:

sets the handling of warning messages. If warn is negative all warnings are ignored. If warn is zero (the default) warnings are stored until the top–level function returns. If 10 or fewer warnings were signalled they will be printed otherwise a message saying how many were signalled. An object called last.warning is created and can be printed through the function warnings. If warn is one, warnings are printed as they occur. If warn is two or larger all warnings are turned into errors.

In that sense, setting options(warn = 1) before the sink makes it possible for the warning messages can be captured. The warn can be reverted to default after resetting the sink (i.e., options(warn = 0)). Then, fun would look something like:

fun <- function() {
    # Print warnings as they occur.
    options(warn = 1)

    # Create variable to store the warnings.
    warns <- vector("character")

    # Create connection for the sink.
    connection <- textConnection("warns", "wr", local = TRUE)

    # Start collecting.
    sink(connection, type = "message")

    # Call external function and produce a warning.
    external()

    # Reset the sink.
    sink(type = "message")

    # Close the connection.
    close(connection)

    # Restore default warning behavior.
    options(warn = 0)

    return(warns)
}

With the following output:

fun()
# [1] "Warning in external() : warning from external..."
Mihai
  • 2,807
  • 4
  • 28
  • 53