R номера строк скрипта при ошибке?


Если я запускаю длинный R-скрипт из командной строки (R -- slave script.R), как я могу заставить его дать номера строк при ошибках?

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

5 86

5 ответов:

это не даст вам номер строки, но он скажет вам, где сбой происходит в стеке вызовов, что очень полезно:

traceback()

[Edit:] при запуске скрипта из командной строки вам придется пропустить один или два звонка, см. traceback () для интерактивных и неинтерактивных сеансов R

Я не знаю другого способа сделать это без обычной отладки подозреваемые:

  1. debug ()
  2. browser ()
  3. options(error=recover) [затем options (error = NULL), чтобы вернуть его]

вы, возможно, захотите взглянуть на это соответствующую должность.

[Edit:] извините...просто увидел, что вы работаете из командной строки. В этом случае я бы предложил работать с функциональностью options(error). Вот простой пример:

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

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

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

делаешь options(error=traceback) предоставляет немного больше информации о содержании линий, ведущих к ошибке. Он вызывает трассировку, чтобы появиться, если есть ошибка, и для некоторых ошибок он имеет номер строки, префикс #. Но это удар или промах, многие ошибки не получат номера строк.

поддержка этого будет доступна в R 2.10 и более поздних версиях. Дункан Мердок только что отправил в r-devel 10 сентября 2009 года о findLineNum и setBreapoint:

I've just added a couple of functions to R-devel to help with
debugging.  findLineNum() finds which line of which function corresponds
to a particular line of source code; setBreakpoint() takes the output of
findLineNum, and calls trace() to set a breakpoint there.

These rely on having source reference debug information in the code.
This is the default for code read by source(), but not for packages.  To
get the source references in package code, set the environment variable
R_KEEP_PKG_SOURCE=yes, or within R, set options(keep.source.pkgs=TRUE),
then install the package from source code.  Read ?findLineNum for
details on how to
tell it to search within packages, rather than limiting the search to
the global environment.

For example,

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

This will print

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

and you can use

setBreakpoint("<text>#3")

to set a breakpoint there.

There are still some limitations (and probably bugs) in the code; I'll
be fixing thos

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

как я его настроил, обработка ошибок также создает файл RData, содержащий все объектов в рабочей памяти на момент ошибки. Этот дамп можно прочитать обратно в R с помощью load() и затем различные среды, как они существовали на момент ошибки могут быть проверены в интерактивном режиме с помощью debugger(errorDump).

отмечу, что мне удалось получить номера строк в traceback() вывод из любых пользовательских функций в стеке, но только если я использовал при вызове source() для любых пользовательских функций, используемых в моем скрипте. Без этой опции, установка глобальная опция обработки ошибок, как показано ниже, отправила полный вывод traceback() в журнал ошибок с именем error.log, но номера были не доступны.

вот общие шаги, которые я предпринял в своем рабочем процессе, и как я смог получить доступ к дампу памяти и журналу ошибок после неинтерактивного сбоя R.

  1. я поставил следующее в верхней части основного скрипта, который я вызывал из командной строки. Это задает параметр глобальной обработки ошибок для сеанса 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()}))
    
  2. убедитесь, что из основного скрипта и любых последующих вызовов функций в любое время, когда функция получена, опция есть. То есть, чтобы создать функцию, вы должны использовать 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. файл дампа RData с именем errorDump.rda и и журнал ошибок с именем error.log создаются в каталоге, указанном '~/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.rda в интерактивный сеанс R с помощью load('~/path/to/errorDump.rda'). После загрузки, позвоните debugger(errorDump) для просмотра всех объектов R в памяти в любой из активных сред. Смотрите справку R на debugger() для получения дополнительной информации.

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

Вы делаете это путем установки

options(show.error.locations = TRUE)

Мне просто интересно, почему этот параметр не по умолчанию в R? Так и должно быть, как и на любом другом языке.