【问题标题】:How to prevent truncation of error messages in R如何防止截断 R 中的错​​误消息
【发布时间】:2018-10-27 11:58:30
【问题描述】:

我正在使用 RJDBC 查询 R 中的数据库。查询是根据从文件中读取的数据构建的。这些查询可能会变得很长,并且可能包含不存在的列(导致错误)。

下面是一个简化的例子,它将文件作为输入,并运行从文件生成的 2 个查询。

表列 饮料费用 喝糖 饮料量 食物成本
SELECT column, cost, sugar FROM drinks;
SELECT cost FROM food;

由于这些查询可能会变得很长,因此数据库中的任何错误通常会在有用信息之前被截断。我当前的错误之一是:

ERROR [2018-05-16 16:53:07] 处理 DAR-2018-00008 原始错误消息的表 data_baseline_biosamples 时出错:.verify.JDBC.result(r, "Unable to retrieve JDBC result set for " , : 无法检索 SELECT ed.studyid, {very long list of columns} 的 JDBC 结果集 ,ct.nmr_xl_vldl_pl,ct.nmr_xl_

由于数据库错误包括关键信息之前的整个查询,截断删除了对解决问题有价值的信息。

在这种情况下,错误消息可能以如下内容结尾:

(第 1 行,“littlefeltfangs”拥有的表“data_biosamples”不包含“sample_source”列。)

如何记录数据库发送的完整错误消息或提取该消息的最后部分?

我在 tryCatch 中捕获错误并使用 futile.logger 将错误传递到日志文件中。截断后的总错误长度为 8219 个字符,其中 8190 个似乎来自数据库。

【问题讨论】:

标签: r error-handling rjdbc


【解决方案1】:

切断错误消息的不是RJDBC

?stop:

错误将被截断为getOption("warning.length") 个字符,默认为 1000。

所以你可以设置选项:

stop(paste(rep(letters, 50L), collapse = ''))
options(warning.length = 2000L)
stop(paste(rep(letters, 50L), collapse = ''))

您会注意到第一条消息中的截断,但第二条则没有。

对于我自己的从RDJBC 捕获错误的辅助函数,我使用类似:

result = tryCatch(<some DB operation>, error = identity)

然后对result$message 执行正则表达式以测试各种常见错误并生成更友好的错误消息。


?stop 中没有提到的是warning.length 只能在相当窄的值范围内。为了探索这一点,我运行了以下代码:

old = options('warning.length')
can = vapply(1:16000L, function(ii) {
  !is.error(tryCatch(options(warning.length=ii), error=identity))
}, logical(1L))
options(old)

png('~/Desktop/warning_valid.png')
plot(can, las = 1L, ylab = 'Valid option value?',
     main = 'Valid option values for `warning.length`',
     type = 's', lwd = 3L, log = 'x')
first = which.max(can)
switches = c(first, first + which.min(can[first:length(can)] - 1L))
abline(v = switches, lty = 2L, col = 'red', lwd = 2L)
axis(side = 1L, at = switches, las = 2L, cex = .5)
dev.off()

我不确定 100 的最小值,但 8172 是 8192 - 20(20 个字符足以包含 [... truncated])。 Here 是 R 源代码中硬编码这些值的地方,here 是定义缓冲区大小 8192 的地方。

FWIW,在我自己的错误解析辅助函数(为查询 PrestoDB 构建)中,我有这一行:

core_msg = gsub('.*(Query failed.*)\\)\\s*$', '\\1', result$message)

这是为了迎合 PrestoDB 中的错误消息,因此您必须自己自定义它,但我们的想法是剪掉错误消息的那部分,它只是反刍查询本身。

当然,您也可以将result$message 拆分为两个小于8172 字符的位,然后分别打印出来。

【讨论】:

  • 使用tryCatch() 是个好主意。你救了我这么多痛苦。
【解决方案2】:

虽然不是针对一般情况的解决方案,但针对我的具体情况的解决方案是从使用 RJDBC 包转移到 odbc 包(而不是 RODBC 包)。两者都基于 DBI,这意味着切换应该像安装 ODBC 驱动程序和替换 dbConnect 参数一样简单。 odbc 包产生的错误消息不包括原始查询,所以不要遇到我一直在努力解决的截断问题。

作为比较,这是我需要进行的全部更改:

原文:

request_settings[['db_con']]<-dbConnect(global_settings$ingresJDBC,url="jdbc:ingres://localhost:IJ7/myvnode::mydatabase;")

新:

request_settings[['db_con']]<-dbConnect(odbc::odbc(),driver="Ingres",server="myvnode",database="mydatabase")

错误消息更加简洁。例如,

new_result(connection@ptr, statement) 中的错误: nanodbc/nanodbc.cpp:1344: 42501: [Actian][Ingres ODBC Driver][Ingres] 第 1 行,'littlefeltfangs' 拥有的表 'mytable' 不包含列'mycolumn'。

odbc 包的文档(有什么)可以在here找到。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-12
    • 1970-01-01
    • 2020-06-29
    • 2014-09-02
    • 1970-01-01
    • 1970-01-01
    • 2016-04-22
    • 1970-01-01
    相关资源
    最近更新 更多