Get Current Stack Trace in Ruby Without Raising an Exception

Get current stack trace in Ruby without raising an exception

You can use Kernel#caller:

# /tmp/caller.rb

def foo
puts caller # Kernel#caller returns an array of strings
end

def bar
foo
end

def baz
bar
end

baz

Output:

caller.rb:8:in `bar'
caller.rb:12:in `baz'
caller.rb:15:in `<main>'

How do I get ruby to print a full backtrace instead of a truncated one?

Exception#backtrace has the entire stack in it:

def do_division_by_zero; 5 / 0; end
begin
do_division_by_zero
rescue => exception
puts exception.backtrace
raise # always reraise
end

(Inspired by Peter Cooper's Ruby Inside blog)

How to get a stack trace object in Ruby?

You can use Kernel.caller for this. The same method is used when generating stack traces for exceptions.

From the docs:

def a(skip)
caller(skip)
end
def b(skip)
a(skip)
end
def c(skip)
b(skip)
end
c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10"]
c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11"]
c(2) #=> ["prog:8:in `c'", "prog:12"]
c(3) #=> ["prog:13"]

How to show stack trace without error in R?

If you want to see the call stack without an error being thrown, you could try something like this:

show_stack <- function() {
cat("#----- Stack containing call to show_stack -----#\n\n")
x <- sys.calls()
lapply(head(x, -1), function(x) {print(x); cat("\n")})
cat("#-----------------------------------------------#\n\n")
}

Which you just insert in whichever function you want to trace:

foo <- function() bar()
bar <- function() baz()
baz <- function() show_stack()

Resulting in:

foo()
#> #----- Stack containing call to show_stack -----#
#>
#> foo()
#>
#> function() bar()
#>
#> function() baz()
#>
#> #-----------------------------------------------#

Or, for a more real-world example:

my_mean <- function(x) {
show_stack()
sum(x)/length(x)
}

Which may be run multiple times in a call:

tapply(iris$Sepal.Length, iris$Species, my_mean)
#> #----- Stack containing call to show_stack -----#
#>
#> tapply(iris$Sepal.Length, iris$Species, my_mean)
#>
#> lapply(X = ans[index], FUN = FUN, ...)
#>
#> FUN(X[[i]], ...)
#>
#> #-----------------------------------------------#
#>
#> #----- Stack containing call to show_stack -----#
#>
#> tapply(iris$Sepal.Length, iris$Species, my_mean)
#>
#> lapply(X = ans[index], FUN = FUN, ...)
#>
#> FUN(X[[i]], ...)
#>
#> #-----------------------------------------------#
#>
#> #----- Stack containing call to show_stack -----#
#>
#> tapply(iris$Sepal.Length, iris$Species, my_mean)
#>
#> lapply(X = ans[index], FUN = FUN, ...)
#>
#> FUN(X[[i]], ...)
#>
#> #-----------------------------------------------#
#>
#> setosa versicolor virginica
#> 5.006 5.936 6.588

Rails: Logging the entire stack trace of an exception

If you look at the source for the BufferedLogger class in ActiveSupport, you'll see that the second argument is 'progname'. This is used only when the first argument is nil and you have either given it no block or the block return a non-true value.

In essence, you can't use the second parameter to output additional stuff.

What you want to do is something more akin to:

begin
raise
rescue => e
logger.error e.message
logger.error e.backtrace.join("\n")
end

Depending on how you have your logging setup, it might be better to iterate through each line of the backtrace and print it separately as certain loggers don't output newlines, in which case you'd do something like:

begin
raise
rescue => e
logger.error e.message
e.backtrace.each { |line| logger.error line }
end

Why raise an exception with the current method removed from the stack trace?

The reason that seems useful to me is so that the stack trace can most clearly point the user of the library to the source of the problem. My copy of Programming Ruby didn't provide any more insight than yours did, but The Ruby Programming Language confirms my feelings with this:

The intent of the exception we're raising here is to point out a problem with the invocation of the ... method, not with the code inside the method. ... If we want to point directly to the problem code, we can provide a custom stack trace as the third argument to raise with ... caller.

Is it possible to extract locals and their values from a stack trace in Ruby?

It is not easy to do it yourself, but there is a gem binding_of_caller (gem) written by banisterfiend that makes it possible.



Related Topics



Leave a reply



Submit