This was the tip of the week in the March 4, 2021 Ruby Weekly Newsletter.
Have you ever needed to know the execution stack for a call? Perhaps you’re looking to provide a useful logging message with the entire stacktrace? Or you want to know where a specific method was called? Or you’re writing a gem and need to know where a method is being used?
In any of these cases, you’re in luck because from Ruby 2.0 onwards we have access to
Kernel#caller_locations which gives us an array of
Thread::Backtrace::Location objects which represent the current execution stack.
Here’s a simple little example with three methods, where the third method calls the second method which calls the first method which in turn tells us the
def method_one caller_locations end def method_two method_one end def method_three method_two end pp method_three
If we run this snippet (saved in a file called
example.rb), we’ll get:
$ ruby example.rb ["example.rb:6:in `method_two'", "example.rb:10:in `method_three'", "example.rb:13:in `<main>'"]
We can see our stacktrace!
Kernel#caller_locations can take two optional parameters which both work to limit the size of the array of
Thread::Backtrace::Location objects we receive. The first (
start) parameter tells how many stack entries to omit from the top of the stack. The second (
length) parameter tells how many objects to include in the returned Array.
A common use of
caller_locations is getting the first element to see the calling method. This can be done by passing in the arguments
(1,1). If we modify our code slightly to use
caller_locations(1,1), we’ll get:
$ ruby example.rb ["example.rb:6:in `method_two'"]
And we can see that
method_two is calling
method_one. Lastly, there are a few useful methods on Thread::Backtrace::Location objects. The most notable ones are
#path which give us the line number, method name and file path respectively.