Сохранить трассировку при ошибке с помощью tryCatch

При вызове функции R внутри моего веб-приложения я хотел бы перехватить трассировку стека при возникновении ошибки и представить ее пользователю для целей отладки. Что-то вроде вывода traceback() в интерактивном сеансе. Однако traceback, кажется, не работает, когда он вызывается внутри обработчика ошибок, он возвращает No traceback available:

f <- function() {
    g <- function() stop("test traceback")
    g()
}

errhandler <- function(e){
  stacktrace <- traceback()
  unlist(stacktrace);
}

out <- tryCatch(f(), error=errhandler) 

Есть ли способ программно поймать трассировку стека ошибки? т.е. получить вывод, который я получил бы при вызове traceback() вручную после ошибки:

f()
traceback()

person Jeroen    schedule 02.06.2013    source источник


Ответы (3)


Оказывается, в последней версии пакета evaluate есть функция с именем try_capture_stack, которая довольно хорошая реализация этого.

person Jeroen    schedule 02.06.2013
comment
Каковы плохие побочные эффекты использования .try_quietly? - person Kevin Krouse; 20.03.2014

Функция tools:::.try_quietly делает нечто подобное:

f <- function() {
  g <- function() stop("test traceback")
  g()
}

tools:::.try_quietly(f()) 

Error: test traceback
Call sequence:
3: stop("test traceback")
2: g()
1: f()

Однако ошибки и предупреждения выводятся в outConn с помощью sink() — это означает, что вы не можете напрямую присвоить результаты объекту. Чтобы обойти это, вам, возможно, придется изменить код, чтобы использовать print() вместо sink (не пробовали).

person Andrie    schedule 02.06.2013
comment
Я также нашел этот, но он имеет много неприятных побочных эффектов и плохо сочетается с tryCatch и т. д. - person Jeroen; 03.06.2013

У меня не получилось получить стек как при трассировке с try_capture_stack, поэтому я написал решение, которое работает как try, за исключением того, что оно еще и возвращает стек вызовов. tools:::.try_quietly аккуратно, но не сохраняет стеки для последующей проверки...

tryStack <- function(
expr,
silent=FALSE
)
{
tryenv <- new.env()
out <- try(withCallingHandlers(expr, error=function(e)
  {
  stack <- sys.calls()
  stack <- stack[-(2:7)]
  stack <- head(stack, -2)
  stack <- sapply(stack, deparse)
  if(!silent && isTRUE(getOption("show.error.messages"))) 
    cat("This is the error stack: ", stack, sep="\n")
  assign("stackmsg", value=paste(stack,collapse="\n"), envir=tryenv)
  }), silent=silent)
if(inherits(out, "try-error")) out[2] <- tryenv$stackmsg
out
}

lower <- function(a) a+10
upper <- function(b) {plot(b, main=b) ; lower(b) }

d <- tryStack(upper(4))
d <- tryStack(upper("4"))
cat(d[2])

Дополнительная информация в моем ответе здесь: https://stackoverflow.com/a/40899766/1587132

person Berry Boessenkool    schedule 30.11.2016
comment
Хотя теоретически это может ответить на вопрос, было бы предпочтительнее включить основные части ответа на этот конкретный вопрос здесь и предоставить ссылка для ознакомления. Это также относится к другим ответам, которые вы недавно добавили. - person Pierre L; 01.12.2016