R строки сценария номера при ошибке? - PullRequest
95 голосов
/ 18 сентября 2009

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

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

Ответы [ 6 ]

41 голосов
/ 18 сентября 2009

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

traceback()

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

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

  1. отладки ()
  2. браузер ()
  3. параметры (ошибка = восстановление) [с последующими параметрами (ошибка = NULL), чтобы вернуть его]

Возможно, вы захотите посмотреть этот пост.

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

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

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

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

11 голосов
/ 23 октября 2012

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

9 голосов
/ 18 сентября 2009

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

Например,

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

чтобы установить точку останова.

В коде все еще есть некоторые ограничения (и, возможно, ошибки); Больной исправь это

5 голосов
/ 11 октября 2016

Вы делаете это, устанавливая

options(show.error.locations = TRUE)

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

3 голосов
/ 10 сентября 2017

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

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

Замечу, что мне удалось получить номера строк в выводе traceback() из любых пользовательских функций в стеке, но только если я использовал опцию keep.source=TRUE при вызове 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. Убедитесь, что из основного скрипта и любых последующих вызовов функций, каждый раз, когда функция вызывается, используется опция keep.source=TRUE. То есть для источника функции вы должны использовать 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-сеансы, инициируемые в командной строке, и вы хотите сохранить информацию о непредвиденных ошибках. Возможность выгрузки памяти в файл, который вы можете использовать для проверки рабочей памяти во время ошибки, наряду с наличием номеров строк ошибки в стеке вызовов, способствует быстрой посмертной отладке того, что вызвало ошибку.

0 голосов
/ 09 января 2019

Сначала options(show.error.locations = TRUE), а затем traceback(). Номер строки ошибки будет отображаться после #

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...