Как предотвратить усечение сообщений об ошибках в R - PullRequest
0 голосов
/ 17 мая 2018

Я запрашиваю базу данных в R, используя RJDBC. Запросы составляются из данных, которые считываются из файла. Эти запросы могут быть очень длинными и потенциально могут включать несуществующие столбцы (что приводит к ошибке).

Ниже приведен упрощенный пример, он принимает файл в качестве входных данных и запускает 2 запроса, сгенерированных из файла.

table     column
drinks    cost
drinks    sugar
drinks    volume
food      cost
SELECT column, cost, sugar FROM drinks;
SELECT cost FROM food;

Поскольку эти запросы могут быть очень длинными, любые ошибки в базе данных часто обрезаются до получения полезной информации. Одна из моих текущих ошибок гласит:

ОШИБКА [2018-05-16 16:53:07] Ошибка при обработке таблицы data_baseline_biosamples для исходного сообщения об ошибке DAR-2018-00008: Ошибка в .verify.JDBC.result (r, «Невозможно получить набор результатов JDBC для» ,: Невозможно получить набор результатов JDBC для SELECT ed.studyid, {очень длинный список столбцов}, ct.nmr_xl_vldl_pl, ct.nmr_xl_

Поскольку ошибка базы данных включает весь запрос до ключевой информации, усечение удаляет ценную информацию для решения проблемы.

В этом случае сообщение об ошибке, вероятно, заканчивается примерно так:

(строка 1, таблица «data_biosamples», принадлежащая «littlefeltfangs», не содержит столбец «sample_source».)

Как записать полное сообщение об ошибке, отправленное базой данных, или каким-либо другим способом извлечь окончательную часть этого сообщения?

Я фиксирую ошибку в tryCatch и передаю ошибку в файл журнала, используя futile.logger. Общая длина ошибки при усечении составляет 8219 символов, из них 8190 - из базы данных.

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Хотя это не решение для общего случая, решение для моего конкретного случая состояло в том, чтобы перейти от использования пакета 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, оператор): nanodbc / nanodbc.cpp: 1344: 42501: [Actian] [Драйвер ODBC Ingres] [Ingres] строка 1, таблица «mytable»принадлежащий 'littlefeltfangs' не содержит столбца 'mycolumn'.

Документацию по пакету odbc (что он есть) можно найти здесь .

0 голосов
/ 17 мая 2018

Это не 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 может быть только в довольно узком диапазоне значений. Чтобы изучить это, я запустил следующий код:

can = logical(16000L)
for (ii in seq_along(can)) {
  res = tryCatch(options(warning.length = ii),
                 error = identity)
  if (inherits(res, 'error')) {
    can[ii] = FALSE
  } else can[ii] = TRUE
}

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()

enter image description here

Ударяет меня, откуда взялись эти числа (100 и 8172), они кажутся довольно произвольными (8196 - ближайшая степень 2). Здесь - это место в источнике R, где эти значения жестко запрограммированы. Я спросил об этом в r-devel; Я обновлю этот пост соответственно.

FWIW, в моей собственной вспомогательной функции синтаксического анализа ошибок (созданной для запросов к PrestoDB) у меня есть эта строка:

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

Это относится к сообщениям об ошибках, которые приходят из PrestoDB, поэтому вам придется настроить его самостоятельно, но идея состоит в том, чтобы вырезать ту часть вашего сообщения об ошибке, которая просто отрыгивает сам запрос.

В качестве альтернативы, конечно, вы можете разбить result$message на два бита, длина которых не превышает 8172 символов, и распечатать их отдельно.

...