R script номера строк при ошибке?
Если я запускаю длинный R script из командной строки (R --slave script.R), как я могу заставить его указывать номера строк при ошибках?
Я не хочу добавлять команды отладки в script, если это вообще возможно - я просто хочу, чтобы R вел себя как большинство других языков сценариев...
Ответы
Ответ 1
Это не даст вам номер строки, но он скажет вам, где происходит сбой в стеке вызовов, что очень полезно:
traceback()
[Edit:] При запуске script из командной строки вам придется пропустить один или два вызова, см. traceback() для интерактивных и неинтерактивные сеансы R
Я не знаю другого способа сделать это без обычных подозреваемых отладки:
- отладки()
- браузер()
- options (error = recover) [после чего опции (error = NULL) возвращают его]
Возможно, вам стоит посмотреть на эту статью.
[Edit:] Извините... просто увидел, что вы запускаете это из командной строки. В этом случае я предлагаю работать с функциональными возможностями (ошибкой). Вот простой пример:
options(error = quote({dump.frames(to.file=TRUE); q()}))
Вы можете создать в качестве сложного script, как вы хотите, при условии ошибки, поэтому вам нужно просто решить, какую информацию вам нужно для отладки.
В противном случае, если есть определенные области, о которых вы беспокоитесь (например, подключение к базе данных), затем заверните их в функцию tryCatch().
Ответ 2
Выполнение options(error=traceback)
предоставляет немного больше информации о содержимом строк, ведущих к ошибке. Это приводит к тому, что traceback появляется, если есть ошибка, а для некоторых ошибок номер строки имеет префикс #
. Но он попал или промахнулся, многие ошибки не получат номера строк.
Ответ 3
Поддержка этого будет в R 2.10 и позже. Дункан Мердок только что опубликовал 10 сентября 2009 года r-devel о findLineNum и setBreapoint:
Я только что добавил несколько функций в R-devel, чтобы помочь с отладкой. findLineNum()
находит, какая строка какой функции соответствует конкретной строке исходного кода; setBreakpoint()
принимает выходные данные findLineNum
и вызывает trace()
для установки там точки останова.
Они полагаются на наличие в коде отладочной информации ссылки на источник. Это значение по умолчанию для кода, читаемого source()
, но не для пакетов. Чтобы получить исходные ссылки в коде пакета, задайте переменную среды R_KEEP_PKG_SOURCE=yes
или в R установите options(keep.source.pkgs=TRUE)
, затем установите пакет из исходного кода. Прочтите ?findLineNum
чтобы узнать, как ?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")
установить точку останова там.
В коде все еще есть некоторые ограничения (и, возможно, ошибки); Я исправлю это
Ответ 4
Вы сделаете это, установив
options(show.error.locations = TRUE)
Мне просто интересно, почему этот параметр не является значением по умолчанию в R? Это должно быть, как и на любом другом языке.
Ответ 5
Указание глобальной опции R для обработки некатастрофических ошибок, сработанных для меня, а также настраиваемый рабочий процесс для сохранения информации об ошибке и изучения этой информации после сбоя. В настоящее время я запускаю R версии 3.4.1.
Ниже я включил описание рабочего процесса, который работал у меня, а также некоторый код, который я использовал для установки глобальной функции обработки ошибок в R.
Как я уже настроил, обработка ошибок также создает файл RData, содержащий все объекты в рабочей памяти во время ошибки. Этот дамп можно прочитать в R с помощью load()
, а затем различные среды, которые существовали во время ошибки, могут быть инспектированы в интерактивном режиме с помощью debugger(errorDump)
.
Отмечу, что мне удалось получить номера строк в traceback()
выводах любых пользовательских функций в стеке, но только если я использовал параметр keep.source=TRUE
при вызове source()
для любых пользовательских функций, используемых в моем script. Без этой опции установка глобальной функции обработки ошибок, как показано ниже, отправила полный вывод traceback()
в журнал ошибок с именем error.log
, но номера строк не были доступны.
Вот основные шаги, которые я предпринял в своем рабочем процессе и как я смог получить доступ к дампу памяти и журналу ошибок после неинтерактивного R-сбоя.
-
Я поставил следующее в верхней части основного script, который я вызывал из командной строки. Это задает параметр глобальной обработки ошибок для сеанса R. Мой главный script был вызван 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()}))
-
Удостоверьтесь, что из основного script и любых последующих вызовов функций, в любое время при использовании функции используется опция keep.source=TRUE
. То есть, чтобы вызвать функцию, вы должны использовать source('~/path/to/myFunction.R', keep.source=TRUE)
. Это необходимо для вывода traceback()
, чтобы содержать номера строк. Похоже, что вы также можете установить этот параметр во всем мире с помощью options( keep.source=TRUE )
, но я не тестировал его, чтобы убедиться, что он работает. Если вам не нужны номера строк, вы можете опустить эту опцию.
- От терминала (за пределами R) вызовите основной script в пакетном режиме, используя
Rscript myMainScript.R
. Это запустит новый неинтерактивный сеанс R и запустит script myMainScript.R
. Фрагмент кода, указанный в шаге 1, который был помещен в начало myMainScript.R
, устанавливает параметр обработки ошибок для неинтерактивного сеанса R.
- Встречайте ошибку где-то внутри выполнения
myMainScript.R
. Это может быть в самом главном script или глубоко вложенных нескольких функциях. Когда ошибка встречается, обработка будет выполняться, как указано на шаге 1, и сеанс R завершится.
- Файл с дампом RData с именем
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 в памяти в любой из активных сред. См. Справку R на debugger()
для получения дополнительной информации.
Этот рабочий процесс чрезвычайно полезен при запуске R в какой-либо производственной среде, где вы запускаете неинтерактивные R-сеансы в командной строке, и вам нужна информация о непредвиденных ошибках. Возможность сбрасывать память в файл, который вы можете использовать для проверки рабочей памяти во время ошибки, а также номера строк ошибки в стеке вызовов, облегчает быструю посмертную отладку того, что вызвало ошибку.
Ответ 6
Сначала options(show.error.locations = TRUE)
а затем traceback()
. Номер строки ошибки будет отображаться после #