Kernel#caller_locations
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 caller_locations
:
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 #lineno
, #label
and #path
which give us the line number, method name and file path respectively.