Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

add trace/breakpoint while already in R's browser

Tags:

r

debugging

trace

Edit: for the record, the accepted answer has a significant down-fall in that it re-executes the first n lines of code in the function when re-debugged. This might be okay, but when those lines of code include side-effects (e.g., database updates) and/or long-time calculations, it becomes obvious what is happening. I do not believe R provides the ability to do it "properly" (as some other languages do). Bummer.


Some debuggers allow you to dynamically add breakpoints while in the debugger. Is that functionality possible in R? An example:

quux <- function(..)
{ # line 1
  "line 2"
  "line 3"
  "line 4"
  "line 5"
  "line 6"
}

trace("quux", tracer = browser, at = 3)
# [1] "quux"
quux()
# Tracing quux() step 3 
# Called from: eval(expr, envir, enclos)
# Browse[1]> 
# debug: [1] "line 3"

While debugging, I believe I want to jump ahead in the code. Imagine the function has a few hundred lines of code, and I'd prefer to not step through them.

I'd like to be able to do this, and jump from the current line to the next interesting line, but unfortunately it just continues out of the function.

# Browse[2]>
trace("quux", tracer = browser, at = 5)
# [1] "quux"
# Browse[2]>
c    
# [1] "line 6"
# # (out of the debugger)

The trace call while in the debugger merely added the breakpoint to the original (global) function, as shown if I immediately call the function again:

quux()
# Tracing quux() step 5 
# Called from: eval(expr, envir, enclos)
# Browse[1]> 
# debug: [1] "line 5"

I tried setting both at once (at=c(3,5)) while inside the browser, but this just sets those lines for when I exit the debugger and call the function again.

I'm guessing this has to do with the function to which trace is attaching the breakpoint. Looking into trace (and .TraceWithMethods), I think I need to be setting where, but I cannot figure out how to get it to set a new breakpoint/trace on the in-debugging function.

(The larger picture is that I'm troubleshooting a function that is dealing with a kafka-led stream of data. My two options are currently (a) restart the function with the more appropriate trace, but this requires me to purge and restart the data stream as well; or (b) go line-by-line in the debugger, tedious when there are many hundreds of lines of code.)

like image 951
r2evans Avatar asked Jun 29 '16 16:06

r2evans


People also ask

How do you add a breakpoint in R?

In RStudio, you can set a breakpoint by clicking to the left of the line number, or pressing Shift + F9 .

How do I add a breakpoint to all methods in visual studio?

Press F3 and then press F9 to add a breakpoint.

How do you add a breakpoint in Visual Studio 2022?

Set breakpoints in source code To set a breakpoint in source code: Click in the far left margin next to a line of code. You can also select the line and press F9, select Debug > Toggle Breakpoint, or right-click and select Breakpoint > Insert breakpoint. The breakpoint appears as a red dot in the left margin.


1 Answers

This may be kind of a solution. First do as in your post:

> quux <- function(..)
+ { # line 1
+   x <- 1   # added for illustration
+   "line 3"
+   "line 4"
+   "line 5"
+   print(x) # added for illustration
+   "line 7"
+   "line 8"
+ }
> 
> trace("quux", tracer = browser, at = 4)
[1] "quux"
> quux()
Tracing quux() step 4 
Called from: eval(expr, p)
Browse[1]> n
debug: [1] "line 4"

Next, we do as follows in the debugger:

Browse[2]> this_func <- eval(match.call()[[1]])       # find out which funcion is called
Browse[2]> formals(this_func) <- list()               # remove arguments
Browse[2]> body(this_func) <- body(this_func)[-(2:4)] # remove lines we have evalutaed   
Browse[2]> trace("this_func", tracer = browser, 
+                at = 8 - 4 + 1)                      # at new line - old trace point
Tracing function "this_func" in package "base"
[1] "this_func"
Browse[2]> this_func                                  # print for illustration
function () 
{
    "line 5"
    print(x)
    "line 7"
    "line 8"
}
Browse[2]> environment(this_func) <- environment()    # change enviroment so x is present
Browse[2]> this_func()                                # call this_func
[1] 1
[1] "line 8"

The downside is that we end back at "line 5" in the original call to quux after we exit from the call to this_func. Further, we have to keep track of the last at value. We may be able to get this from another function?

like image 69
Benjamin Christoffersen Avatar answered Sep 17 '22 15:09

Benjamin Christoffersen