如果我从命令行(R --slave script.R)运行一个较长的R脚本,如何获取错误的行号?
我根本不想在脚本中添加调试命令-我只希望R像大多数其他脚本语言一样工作...
如果我从命令行(R --slave script.R)运行一个较长的R脚本,如何获取错误的行号?
我根本不想在脚本中添加调试命令-我只希望R像大多数其他脚本语言一样工作...
Answers:
这不会提供行号,但是会告诉您调用堆栈中失败的位置,这非常有帮助:
traceback()
[编辑:]从命令行运行脚本时,您将不得不跳过一两个调用,有关交互式和非交互式R会话,请参见traceback()
如果没有通常的调试怀疑,我不知道另一种方法:
[编辑:]对不起...只是看到您正在从命令行运行它。在那种情况下,我建议您使用options(error)功能。这是一个简单的例子:
options(error = quote({dump.frames(to.file=TRUE); q()}))
您可以在错误情况下根据需要创建详细的脚本,因此您只需要确定调试所需的信息即可。
否则,如果您担心某些特定区域(例如,连接到数据库),则将它们包装在tryCatch()函数中。
options(error=function() { traceback(2); if(!interactive()) quit("no", status = 1, runLast = FALSE) })
(请参阅已接受答案的注释)。我认为将其添加到此处的答案中而不是仅提供到另一个线程的链接是有意义的。
这样做options(error=traceback)
提供了有关导致错误的行内容的更多信息。如果存在错误,则会导致出现回溯,对于某些错误,它的行号以开头#
。但是无论碰到还是错过,很多错误不会得到行号。
No traceback available
在错误发生后才说。
R 2.10及更高版本将对此提供支持。邓肯·默多克(Duncan Murdoch)于2009年9月10日发布在r-devel上,关于findLineNum和setBreapoint:
我刚刚在R-devel中添加了几个函数来帮助调试。
findLineNum()
查找哪个函数的哪一行对应于特定的源代码行;setBreakpoint()
接受的输出findLineNum
,并调用trace()
在那里设置断点。这些依赖于在代码中具有源引用调试信息。这是读取的代码的默认值
source()
,而不是软件包的默认值。要获取包代码中的源引用,请设置环境变量R_KEEP_PKG_SOURCE=yes
,或在R中设置setoptions(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")
在此处设置断点。
代码中仍然存在一些局限性(可能还有错误)。我会修复
您可以通过设置
options(show.error.locations = TRUE)
我只是想知道为什么该设置不是R中的默认设置?应该如此,就像其他所有语言一样。
指定全局R选项来处理非灾难性错误对我来说很有效,并且自定义工作流用于保留有关错误的信息并在故障后检查此信息。我当前正在运行R版本3.4.1。下面,我提供了适用于我的工作流程的描述,以及一些我用来在R中设置全局错误处理选项的代码。
根据我的配置,错误处理还会在错误发生时创建一个RData文件,其中包含工作内存中的所有对象。可以使用将该转储读回到R load()
,然后可以使用交互检查发生错误时存在的各种环境debugger(errorDump)
。
我将注意到,我能够traceback()
从堆栈中的任何自定义函数的输出中获取行号,但前提是我keep.source=TRUE
在调用source()
脚本中使用的任何自定义函数时使用了该选项。如果没有此选项,则按如下所示设置全局错误处理选项会将的完整输出发送traceback()
到名为的错误日志中error.log
,但是行号不可用。
这是我在工作流程中采取的一般步骤,以及在非交互式R失败后如何访问内存转储和错误日志。
我将以下内容放在从命令行调用的主脚本的顶部。这将为R会话设置全局错误处理选项。我的主脚本叫做myMainScript.R
。代码中的各行之后都有注释,描述了它们的作用。基本上,使用此选项时,当R遇到触发错误的错误时stop()
,它将在目录中的所有活动环境中创建工作内存的RData(* .rda)转储文件,~/myUsername/directoryForDump
并且还将错误日志命名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()}))
确保从主脚本和任何后续函数调用中,无论何时获取函数,keep.source=TRUE
都使用该选项。也就是说,要使用函数,可以使用source('~/path/to/myFunction.R', keep.source=TRUE)
。这是traceback()
输出包含行号所必需的。看来您也可以使用来全局设置此选项options( keep.source=TRUE )
,但我尚未对其进行测试以查看其是否有效。如果不需要行号,则可以省略此选项。
Rscript myMainScript.R
。这将启动一个新的非交互式R会话并运行脚本myMainScript.R
。已放置在步骤1顶部的步骤1中给出的代码段myMainScript.R
设置了非交互式R会话的错误处理选项。myMainScript.R
。这可以在主脚本本身中,也可以嵌套在多个函数中。遇到错误时,将按照步骤1中的指定执行处理,R会话将终止。errorDump.rda
和和名为错误日志error.log
的目录'~/myUsername/directoryForDump'
。在您闲暇时,检查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)
您可以在闲暇时errorDump.rda
使用加载到交互式R会话中load('~/path/to/errorDump.rda')
。加载后,调用debugger(errorDump)
以浏览任何活动环境中内存中的所有R对象。有关debugger()
更多信息,请参见R帮助。
在某些类型的生产环境中运行R时,如果您在命令行中启动了非交互式R会话,并且希望保留有关意外错误的信息,则此工作流程将非常有用。将内存转储到文件中的功能,可以在发生错误时检查工作内存,并且在调用堆栈中具有错误的行号,有助于快速地对导致错误的原因进行事后调试。