获取运行时运行的所有R代码

时间:2015-05-14 15:37:47

标签: r try-catch eval

假设我在脚本中有一堆R代码,并且我想将从.GlobalEnv运行的所有R代码与错误和警告消息一起记录到平面文件或数据库中。 我可以编写一个简单的logme函数,如下所示,或者通过更改options(error = mylogginfunction)

来获取错误更复杂一些
mylogfile <- tempfile()
logme <- function(x){
  mode <- "at"
  if(!file.exists(mylogfile)){
    mode <- "wt"
  }
  myconn <- file(mylogfile, mode)
  writeLines(x, myconn)
  close(myconn)
  invisible()
}

logme(sprintf("%s: started some yadayada, ", Sys.time()))
x <- 10
x * 7
logme(sprintf("%s: done with yadayada", Sys.time()))

## Get the log
cat(readLines(mylogfile))

日志打印出来: 2015-05-14 17:24:31:开始一些yadayada,2015-05-14 17:24:31:用yadayada完成

但我想要的是,日志文件记下了执行的表达式,而不必在每个语句周围编写包装器。 我希望日志看起来像。 2015-05-14 17:24:31:开始一些yadayada, x&lt; - 10,x * 7 2015-05-14 17:24: 31:完成yadayada

所以我的问题是,如何获取R正在执行的内容,以便我可以将执行的表达式存储在日志/数据库中。而且无需在每个表达式之前编写函数调用(如myhandler(x < - 10); myhandler(x * 10))。 对此有何帮助?

3 个答案:

答案 0 :(得分:4)

要捕获输入命令,您可以使用addTaskCallback

mylogfile <- tempfile()
addTaskCallback(
    function(...) { 
        expr <- deparse(as.expression(...)[[1]]) # it could handled better...
        cat(expr, file=mylogfile, append=TRUE, sep="\n")
        # or cat(sprintf("[%s] %s", Sys.time(), expr),...) if you want timestamps
        TRUE
    }
    ,name="logger"
)

x <- 10
x * 7

removeTaskCallback("logger")

然后结果是:

cat(readLines(mylogfile), sep="\n")
... addTaskCallback definition ...
x <- 10
x * 7

但你得到的是解析表达式,这意味着行

x+1;b<-7;b==2

将记录为

x + 1
b <- 7
b == 2

另外:

  • 不会记录输出,特别是控制台
  • 中显示的messagewarning
  • 如果error日志记录不会被触发,那么你需要单独的函数来处理它

答案 1 :(得分:0)

这可能在每种情况下都很简单,但你可以试试这个:

将myhandler定义为:

myhandler <- function(x, file = stdout()) {
  expr <- substitute(x)
  for(e_line in as.list(expr)) {
    cat( file = file, as.character(Sys.time()), capture.output(e_line), "\n")
    eval(e_line, envir = parent.frame())
  }
}

将它与括号内的代码一起使用:

myhandler({

  a <- 1
  a <- a + 1
  print(a)

})

结果:

# 2015-05-14 18:46:34 `{` 
# 2015-05-14 18:46:34 a <- 1 
# 2015-05-14 18:46:34 a <- a + 1 
# 2015-05-14 18:46:34 print(a) 
# [1] 2

答案 2 :(得分:0)

我承认,我并没有真正得到什么&#34;让运行的表达式在与R命令运行的相同过程中可用#34;意味着我们在评论中聊了一下。但是,我扩展了我的想法。您可以使用以下行创建logGenerator.R文件:

logGenerator<-function(sourcefile,log) {
  ..zz <- file(log, open = "at")
  sink(..zz)
  sink(..zz, type = "message")
  on.exit({
    sink(type="message")
    sink()
    close(..zz)
  })
  ..x<-parse(sourcefile)
  for (..i in 1:length(..x)) {
    cat(as.character(Sys.time()),"\n")
    cat(as.character(..x[..i]),"\n")
    ..y<-eval(..x[..i])
  }
}

此函数将源文件和日志文件名作为参数。该脚本将采用R文件并记录每条指令的执行时间。然后它将表达式记录在同一个日志文件中。定向到stdout()的每个输出和错误消息都定向到日志文件。您显然不必以任何方式修改源文件。