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(). Номер строки ошибки будет отображаться после #