R脚本行号错误?

时间:2009-09-18 17:47:30

标签: debugging r

如果我从命令行运行一个长R脚本(R --slave script.R),我怎样才能让它给出错误的行号?

如果可能的话,我不想将调试命令添加到脚本中 - 我只是希望R的行为与大多数其他脚本语言一样......

6 个答案:

答案 0 :(得分:41)

这不会给你行号,但它会告诉你调用堆栈中发生故障的位置非常有帮助:

traceback()

[编辑:] 从命令行运行脚本时,您必须跳过一两个电话,请参阅traceback() for interactive and non-interactive R sessions

如果没有通常的调试嫌疑人,我不知道另一种方法:

  1. 调试()
  2. 浏览器()
  3. options(error = recover)[后跟选项(错误= NULL)以还原它]
  4. You might want to look at this related post.

    [编辑:] 抱歉...刚刚看到你从命令行运行它。在这种情况下,我建议使用选项(错误)功能。这是一个简单的例子:

    options(error = quote({dump.frames(to.file=TRUE); q()}))
    

    您可以根据需要在错误情况下创建详尽的脚本,因此您应该只决定调试所需的信息。

    否则,如果您关注的是特定区域(例如连接到数据库),请将它们包装在tryCatch()函数中。

答案 1 :(得分:11)

执行options(error=traceback)提供了有关导致错误的行内容的更多信息。如果出现错误,它会导致出现回溯,对于某些错误,它会有行号,前缀为#。但它的命中或错过,很多错误都不会得到行号。

答案 2 :(得分:9)

R 2.10及更高版本即将支持此项。 Duncan Murdoch于2009年9月10日刚刚向r-devel发布关于findLineNum and setBreapoint

的消息
  

我刚刚为R-devel添加了一些功能来帮助   调试。 findLineNum()找到哪个函数的哪一行   对应于特定的源代码行; setBreakpoint()需要   findLineNum的输出,并调用trace()来设置断点   那里。

     

这些依赖于代码中的源参考调试信息。   这是source()读取的代码的默认值,但不适用于包。   要在包代码中获取源引用,请设置环境   变量R_KEEP_PKG_SOURCE=yes或R内的集合   options(keep.source.pkgs=TRUE),然后从源安装包   码。请阅读?findLineNum,了解有关如何告知其搜索的详细信息   在包内,而不是将搜索限制在全局范围内   环境。

     

例如,

x <- " f <- function(a, b) {
             if (a > b)  {
                 a
             } else {
                 b
             }
         }"


eval(parse(text=x))  # Normally you'd use source() to read a file...

findLineNum("<text>#3")   # <text> is a dummy filename used by
parse(text=)
     

这将打印

 f step 2,3,2 in <environment: R_GlobalEnv>
     

你可以使用

setBreakpoint("<text>#3")
     

在那里设置断点。

     

代码中仍然存在一些限制(可能是错误);生病   正在修理这个

答案 3 :(得分:5)

您可以通过设置

来实现
options(show.error.locations = TRUE)

我只是想知道为什么这个设置不是R的默认设置?它应该是,就像所有其他语言一样。

答案 4 :(得分:3)

指定用于处理非灾难性错误的全局R选项,以及用于保留错误信息并在失败后检查此信息的自定义工作流程。我目前正在运行R版本3.4.1。 下面,我已经包含了对我有用的工作流程的描述,以及我用来设置R中的全局错误处理选项的一些代码。

正如我配置的那样,错误处理还会创建一个RData文件,其中包含错误发生时工作内存中的所有对象。可以使用load()将此转储读回到R中,然后可以使用debugger(errorDump)以交互方式检查错误发生时存在的各种环境。

我会注意到,我能够从堆栈中的任何自定义函数的traceback()输出中获取行号,但前提是在调用keep.source=TRUE时使用了source()选项我的脚本中使用的任何自定义函数。如果没有此选项,则按如下所示设置全局错误处理选项会将traceback()的完整输出发送到名为error.log的错误日志,但行号不可用。

以下是我在工作流程中采取的一般步骤,以及在非交互式R故障后我如何能够访问内存转储和错误日志。

  1. 我将以下内容放在我从命令行调用的主脚本的顶部。这将为R会话设置全局错误处理选项。我的主要脚本名为myMainScript.R。代码中的各个行在它们描述它们的作用之后会有注释。基本上,使用此选项,当R遇到触发stop()的错误时,它将在目录~/myUsername/directoryForDump中的所有活动环境中创建工作内存的RData(* .rda)转储文件,并且还将写入一个名为error.log的错误日志,其中包含一些有用的信息到同一目录。您可以修改此代码段以在错误时添加其他处理(例如,向转储文件和错误日志文件名等添加时间戳)。

    options(error = quote({
      setwd('~/myUsername/directoryForDump'); # Set working directory where you want the dump to go, since dump.frames() doesn't seem to accept absolute file paths.
      dump.frames("errorDump", to.file=TRUE, include.GlobalEnv=TRUE); # First dump to file; this dump is not accessible by the R session.
      sink(file="error.log"); # Specify sink file to redirect all output.
      dump.frames(); # Dump again to be able to retrieve error message and write to error log; this dump is accessible by the R session since not dumped to file.
      cat(attr(last.dump,"error.message")); # Print error message to file, along with simplified stack trace.
      cat('\nTraceback:');
      cat('\n');
      traceback(2); # Print full traceback of function calls with all parameters. The 2 passed to traceback omits the outermost two function calls.
      sink();
      q()}))
    
  2. 确保从主脚本和任何后续函数调用中,只要有源函数,就会使用选项keep.source=TRUE。也就是说,要使用函数,您可以使用source('~/path/to/myFunction.R', keep.source=TRUE)。这是traceback()输出包含行号所必需的。看起来您也可以使用options( keep.source=TRUE )全局设置此选项,但我没有对此进行测试以查看它是否有效。如果您不需要行号,则可以省略此选项。

  3. 从终端(R外部),使用Rscript myMainScript.R以批处理模式调用主脚本。这将启动一个新的非交互式R会话并运行脚本myMainScript.R。步骤1中给出的代码片段放在myMainScript.R的顶部,为非交互式R会话设置错误处理选项。
  4. 在执行myMainScript.R的某个地方遇到错误。这可能在主脚本本身,或嵌套了几个函数深。遇到错误时,将按照步骤1中的指定执行处理,R会话将终止。
  5. 在全局错误处理选项设置中,errorDump.rda指定的目录中创建名为error.log的RData转储文件和名为'~/myUsername/directoryForDump'的错误日志。
  6. 闲暇时,请检查error.log以查看有关错误的信息,包括错误消息本身以及导致错误的完整堆栈跟踪。这是一个错误生成的日志示例;请注意#字符后面的数字是调用堆栈中各个点的错误行号:

    Error in callNonExistFunc() : could not find function "callNonExistFunc"
    Calls: test_multi_commodity_flow_cmd -> getExtendedConfigDF -> extendConfigDF
    
    Traceback:
    3: extendConfigDF(info_df, data_dir = user_dir, dlevel = dlevel) at test_multi_commodity_flow.R#304
    2: getExtendedConfigDF(config_file_path, out_dir, dlevel) at test_multi_commodity_flow.R#352
    1: test_multi_commodity_flow_cmd(config_file_path = config_file_path, 
    spot_file_path = spot_file_path, forward_file_path = forward_file_path, 
    data_dir = "../", user_dir = "Output", sim_type = "spot", 
    sim_scheme = "shape", sim_gran = "hourly", sim_adjust = "raw", 
    nsim = 5, start_date = "2017-07-01", end_date = "2017-12-31", 
    compute_averages = opt$compute_averages, compute_shapes = opt$compute_shapes, 
    overwrite = opt$overwrite, nmonths = opt$nmonths, forward_regime = opt$fregime, 
    ltfv_ratio = opt$ltfv_ratio, method = opt$method, dlevel = 0)
    
  7. 闲暇时,您可以使用errorDump.rdaload('~/path/to/errorDump.rda')加载到交互式R会话中。加载后,调用debugger(errorDump)以浏览任何活动环境中内存中的所有R对象。有关详细信息,请参阅debugger()上的R帮助。

  8. 在某些类型的生产环境中运行R时,此工作流程非常有用,您可以在命令行启动非交互式R会话,并且希望保留有关意外错误的信息。将内存转储到可用于在错误发生时检查工作内存的文件的能力,以及在调用堆栈中具有错误的行号,有助于对导致错误的错误进行快速的事后调试。

答案 5 :(得分:0)

首先是options(show.error.locations = TRUE),然后是traceback()。错误行号将显示在#

之后