r - 记录当前函数名称

标签 r function logging

我有一些自定义日志函数,它们是 cat 的扩展。一个基本的例子是这样的:

catt<-function(..., file = "", sep = " ", fill = FALSE, labels = NULL,
    append = FALSE)
{
    cat(..., format(Sys.time(), "(%Y-%m-%d %H:%M:%S)"), "\n", file = file, 
        sep = sep, fill = fill, labels = labels, append = append)
}

现在,我经常使用(自制)函数,并使用其中一些日志函数来查看进度,效果很好。不过,我注意到的是,我几乎总是像这样使用这些函数:
somefunc<-function(blabla)
{
  catt("somefunc: start")
  #do some very useful stuff here
  catt("somefunc: some time later")
  #even more useful stuff
  catt("somefunc: the end")
}

请注意对 catt 的每次调用如何以调用它的函数的名称开头。非常整洁,直到我开始重构我的代码和重命名函数等。

感谢 Brian Ripley 的一些旧的 R-list 帖子,如果我没记错的话,我找到了这段代码来获取“当前函数名称”:
catw<-function(..., file = "", sep = " ", fill = FALSE, labels = NULL,
    append = FALSE)
{
    curcall<-sys.call(sys.parent(n=1))
    prefix<-paste(match.call(call=curcall)[[1]], ":", sep="")
    cat(prefix, ..., format(Sys.time(), "(%Y-%m-%d %H:%M:%S)"), "\n",
        file = file, sep = sep, fill = fill, labels = labels, append = append)
}

这很好,但并不总是有效,因为:
  • 我的函数散落着 lapply 中使用的匿名函数
    函数类型,像这样:

  • aFunc<-function(somedataframe)
    {
      result<-lapply(seq_along(somedataframe), function(i){
      catw("working on col", i, "/", ncol(somedataframe))
      #do some more stuff here and return something
      return(sum(is.na(somedataframe[[i]])))
      }
    }
    


    -> 对于这些情况,显然(并且可以理解)我的 sys.parent 函数中的 catw 调用中需要 n=3。
  • 我偶尔会使用 do.call :它似乎是我当前的实现
    也不起作用(我再一次有点理解它,虽然
    我还没有完全弄清楚。

  • 所以,我的问题是:有没有办法在调用堆栈中找到第一个命名函数(跳过日志函数本身,也许还有其他一些“众所周知的”异常),这将允许我为所有人编写一个单一版本的 catw案例(这样我就可以愉快地重构而不必担心我的日志记录代码)?你会怎么做这样的事情?

    编辑 :应该支持这些情况:
    testa<-function(par1)
    {
        catw("Hello from testa, par1=", par1)
        for(i in 1:2) catw("normal loop from testa, item", i)
        rv<-sapply(1:2, function(i){catw("sapply from testa, item", i);return(i)})
        return(rv)
    }
    
    testb<-function(par1, par2)
    {
        catw("Hello from testb, par1=", par1)
        for(i in 1:2) catw("normal loop from testb, item", i)
        rv<-sapply(1:2, function(i){catw("sapply from testb, item", i);return(i)})
    
        catw("Will now call testa from testb")
        rv2<-testa(par1)
        catw("Back from testa call in testb")
    
        catw("Will now do.call testa from testb")
        rv2<-do.call(testa, list(par1))
        catw("Back from testa do.call in testb")
    
        return(list(rv, rv2))
    }
    
    testa(123)
    testb(123,456)
    do.call(testb, list(123,456))
    

    最佳答案

    编辑:完全重写函数

    此函数的新版本使用调用堆栈,sys.calls() , 而不是 match.call .

    调用栈包含完整的调用函数。所以现在的诀窍是只提取你真正想要的部分。我在 clean_cs 中使用了一些手动清理方法。功能。这将评估调用堆栈中的第一个单词并返回少量已知边缘情况的所需参数,特别是 lapply , sapplydo.call .

    这种方法的唯一缺点是它会一直返回函数名称到调用堆栈的顶部。也许合乎逻辑的下一步是将这些函数与指定的环境/命名空间进行比较,并基于此包含/排除函数名称......

    我会停在这里。它回答了问题中的用例。

    新功能:

    catw <- function(..., callstack=sys.calls()){
      cs <- callstack
      cs <- clean_cs(cs)
      #browser()
      message(paste(cs, ...))
    }
    
    clean_cs <- function(x){
      val <- sapply(x, function(xt){
        z <- strsplit(paste(xt, collapse="\t"), "\t")[[1]]
        switch(z[1],
            "lapply" = z[3], 
            "sapply" = z[3],
            "do.call" = z[2], 
            "function" = "FUN",
            "source" = "###",
            "eval.with.vis" = "###",
            z[1]
            )
        })
      val[grepl("\\<function\\>", val)] <- "FUN"
      val <- val[!grepl("(###|FUN)", val)]
      val <- head(val, -1)
      paste(val, collapse="|")
    }
    

    检测结果:
    testa Hello from testa, par1= 123
    testa normal loop from testa, item 1
    testa normal loop from testa, item 2
    testa sapply from testa, item 1
    testa sapply from testa, item 2
    
    
    testb Hello from testb, par1= 123
    testb normal loop from testb, item 1
    testb normal loop from testb, item 2
    testb sapply from testb, item 1
    testb sapply from testb, item 2
    testb Will now call testa from testb
    testb|testa Hello from testa, par1= 123
    testb|testa normal loop from testa, item 1
    testb|testa normal loop from testa, item 2
    testb|testa sapply from testa, item 1
    testb|testa sapply from testa, item 2
    testb Back from testa call in testb
    testb Will now do.call testa from testb
    testb|testa Hello from testa, par1= 123
    testb|testa normal loop from testa, item 1
    testb|testa normal loop from testa, item 2
    testb|testa sapply from testa, item 1
    testb|testa sapply from testa, item 2
    testb Back from testa do.call in testb
    
    
    testb Hello from testb, par1= 123
    testb normal loop from testb, item 1
    testb normal loop from testb, item 2
    testb sapply from testb, item 1
    testb sapply from testb, item 2
    testb Will now call testa from testb
    testb|testa Hello from testa, par1= 123
    testb|testa normal loop from testa, item 1
    testb|testa normal loop from testa, item 2
    testb|testa sapply from testa, item 1
    testb|testa sapply from testa, item 2
    testb Back from testa call in testb
    testb Will now do.call testa from testb
    testb|testa Hello from testa, par1= 123
    testb|testa normal loop from testa, item 1
    testb|testa normal loop from testa, item 2
    testb|testa sapply from testa, item 1
    testb|testa sapply from testa, item 2
    testb Back from testa do.call in testb
    

    关于r - 记录当前函数名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7307987/

    相关文章:

    r - 尝试在 R 中使用朴素贝叶斯学习器,但 Predict() 给出的结果与模型建议的结果不同

    r - 使用 purrr 时如何自定义 ggplot2 facet_grid 标签中的文本?

    linux - 在linux命令行上按时间戳对日志文件进行排序

    Delphi:如何在不使用断言的情况下获取(当前代码行,当前单元,当前函数)?

    windows - 用于日志记录的基于 Python 时间的旋转文件处理程序

    r - 在查看器 Pane 中打开 R Markdown

    r - 如何解决 devtools 不需要的副作用

    r - 在 R : dcast in function, 中传递列名(再次!)

    C++虚函数问题

    根据 R 中的名称向量删除列