R: Как сделать, чтобы dump.frames() включал все переменные для последующей посмертной отладки с помощью debugger()
У меня есть следующий код, который вызывает ошибку и пишет дамп всех кадров, используя dump.frames()
как предложено, например, Хэдли Уикхем:
a <- -1
b <- "Hello world!"
bad.function <- function(value)
{
log(value) # the log function may cause an error or warning depending on the value
}
tryCatch( {
a.local.value <- 42
bad.function(a)
bad.function(b)
},
error = function(e)
{
dump.frames(to.file = TRUE)
})
Когда я перезапускаю сеанс R и загружаю дамп, чтобы отладить проблему через
load(file = "last.dump.rda")
debugger(last.dump)
Я не могу найти ни мои переменные (a, b, a.local.value), ни мою функцию "bad.function" в кадрах.
Это делает свалку почти бесполезной для меня.
Что мне нужно сделать, чтобы увидеть все мои переменные и функции для достойного посмертного анализа?
Выход из debugger
является:
> load(file = "last.dump.rda")
> debugger(last.dump)
Message: non-numeric argument to mathematical functionAvailable environments had calls:
1: tryCatch({
a.local.value <- 42
bad.function(a)
bad.function(b)
2: tryCatchList(expr, classes, parentenv, handlers)
3: tryCatchOne(expr, names, parentenv, handlers[[1]])
4: value[[3]](cond)
Enter an environment number, or 0 to exit
Selection:
PS: я использую R3.3.2 с RStudio для отладки.
2 ответа
Обратите внимание, что часто с продуктом R Core лучше работать, чем просто рассказывать, что R имеет ошибку. Здесь явно нет ошибки, поскольку она ведет себя точно так, как задокументировано.
Также нет проблем, если вы работаете в интерактивном режиме, поскольку у вас есть полный доступ к вашему рабочему пространству (которое может бытьБОЛЬШИМ), поэтому проблема относится только к пакетным заданиям (как вы упомянули).
Что у нас есть, так этоотсутствие функции, и запросы функций (и отчеты об ошибках!) Должны происходить на сайте ошибок R (он же _'R bugzilla '), https://bugs.r-project.org/... обычно однако после прочтения соответствующей страницы на веб-сайте R: https://www.r-project.org/bugs.html.
Обратите внимание, что R bugzilla доступен для поиска, и в данном случае вы довольно быстро обнаружите, что Андреас Керстинг сделал хорошее предложение (а именно как пожелание, а не претензию на ошибку), https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17116 и, следовательно, я добавил отсутствующую функцию в R уже 16 августа. Да, конечно, версия для разработки R, он же R-devel. Смотрите также сегодняшнюю тему на R-devel
список рассылки, https://stat.ethz.ch/pipermail/r-devel/2016-November/073378.html
Обновление от 20 ноября 2016 года. Обратите внимание, что это не ошибка R (см. Ответ Мартина Мачлера). Я не изменил свой ответ для воспроизводимости. Описанный обходной путь все еще применяется.
Резюме
Я думаю dump.frames(to.file = TRUE)
в настоящее время является антишаблоном (или, возможно, ошибкой) в R, если вы хотите отлаживать ошибки пакетных заданий в новом сеансе R.
Вам лучше заменить его на
dump.frames()
save.image(file = "last.dump.rda")
или же
options(error = quote({dump.frames(); save.image(file = "last.dump.rda")}))
вместо
options(error = dump.frames)
потому что глобальная среда (.GlobalEnv
= пользовательское рабочее пространство, в котором вы обычно создаете свои объекты), затем включается в дамп, но отсутствует, когда вы сохраняете дамп напрямую через dump.frames(to.file = TRUE)
,
Анализ воздействия
Без .GlobalEnv
вы теряете важные объекты верхнего уровня (и их текущие значения;-), чтобы понять поведение вашего кода, которое привело к ошибке!
Особенно в случае ошибок в "неинтерактивных" пакетных заданиях R, без которых вы потерялись .GlobalEnv
поскольку вы можете отлаживать только во вновь запущенном (пустом) интерактивном рабочем пространстве, где вы можете получить доступ только к объектам в кадрах стека вызовов.
Используя приведенный выше фрагмент кода, вы можете проверить значения объектов, которые привели к ошибке в новом рабочем пространстве R, как обычно, с помощью:
load(file = "last.dump.rda")
debugger(last.dump)
Фон
Реализация dump.frames
создает переменную last.dump
в рабочей области и заполняет его средами стека вызовов (sys.frames()
, Каждая среда содержит "локальные переменные" вызываемой функции). Затем он сохраняет эту переменную в файл, используя save()
,
Стек фреймов (стек вызовов) растет с каждым вызовом функции, см. ?sys.frames
:
.GlobalEnv присваивается номер 0 в списке кадров. Каждая последующая оценка функции увеличивает стек фреймов на 1, и среда [...] для оценки этой функции возвращается [...] sys.frame с соответствующим индексом.
Обратите внимание, что .GlobalEnv
имеет индекс номер 0.
Если я сейчас начну отлаживать дамп, созданный кодом в вопросе, и выберу кадр 1 (не 0!), Я смогу увидеть переменную parentenv
какие точки (ссылки) .GlobalEnv
:
Browse[1]> environmentName(parentenv)
[1] "R_GlobalEnv"
Поэтому я считаю, что sys.frames
не содержит .GlobalEnv
и поэтому dump.frames(to.file = TRUE)
ни так как он хранит только sys.frames
без всех других объектов .GlobalEnv
,
Может быть, я ошибаюсь, но это выглядит как нежелательный эффект или даже ошибка. Обсуждения приветствуются!
Рекомендации
https://cran.r-project.org/doc/manuals/R-exts.pdf
Выдержка из раздела 4.2 Отладка кода R (стр. 96):
Поскольку last.dump можно просмотреть позже или даже в другом сеансе R, посмертная отладка возможна даже для пакетного использования R. Нам нужно договориться о сохранении дампа: это можно сделать либо с помощью флаг командной строки - сохранить, чтобы сохранить рабочее пространство в конце цикла или с помощью параметра, такого как
параметры (ошибка = цитата ({dump.frames(to.file=TRUE); q()}))