Ruby has a built-in tracing system which you can access using the TracePoint
class. Some of the things you can trace are method calls, new threads & exceptions.
Why would you want to use this?
Well, it could be useful if you want to trace the execution of a certain method. You will be able to see what other methods are being called & what are the return values.
Let’s see a few examples!
Tracing Method Calls
Most of the time you will want TracePoint
to trace application code & not built-in methods (like puts, size, etc).
You can do this using the call
event.
Example:
def the_method; other_method; end def other_method; end def start_trace trace = TracePoint.new(:call) { |tp| p [tp.path, tp.lineno, tp.event, tp.method_id] } trace.enable yield trace.disable end start_trace { the_method }
This prints the file path, the line number, the event name & the method name.
["test.rb", 1, :call, :the_method] ["test.rb", 2, :call, :other_method]
If you don’t specify any events Ruby will call your block for all of them, resulting in more output. So I would recommend that you focus on specific events to find what you want faster 🙂
Here’s is a table of TracePoint
events:
Event name | Description |
---|---|
call | Application methods |
c_call | C-level methods (like puts) |
return | Method return (for tracing return values & call depth) |
b_call | Block call |
b_return | Block return |
raise | Exception raised |
thread_begin | New thread |
thread_end | Thread ending |
TracePoint + Graphviz
Many methods will make more than just 3 methods calls, especially in framework code, so the output from Tracepoint
can be hard to visualize.
So I made a gem that lets you create a visual call graph like this:
require 'visual_call_graph' VisualCallGraph.trace { "Your method call here..." }
This generates a call_graph.png
file with the results.
Keep in mind that this is not static analysis, this will actually call the method!
Showing File Paths
Would you like to know where these methods are defined?
Don’t worry, I got you covered! I added an option you can enable to show the file path for each method call.
VisualCallGraph.trace(show_path: true) { Foo.aaa }
Which results in:
If you want to see some massive call graphs you just have to trace some Rails methods 😉
Return Values
In the introduction I mentioned that you can also get return values…
For this you will need to trace the return
event and use the return_value
method.
Example:
def the_method; "A" * 10; end trace = TracePoint.new(:return) { |tp| puts "Return value for #{tp.method_id} is #{tp.return_value}." } trace.enable the_method trace.disable
This will print:
Return value for the_method is AAAAAAAAAA.
Events First
Someone asked on reddit how it’s possible to avoid having the word “bar” printed when calling the foo
method in the following code:
class Thing def foo puts "foo" bar end def bar puts "bar" end end # your code here t = Thing.new t.foo
There are many ways to achieve this, like prepending a module, redirecting $stdout
or redefining the bar
method.
If you are feeling creative, comment on this post with your own idea!
But I found one of the answers particularly interesting because it used the TracePoint
class.
Here it is:
TracePoint.trace(:call) { |tp| exit if tp.method_id == :bar }
This code will call exit
when the method bar
is called, which prevents the string from being printed by ending the program.
Probably not something you want to use in real code, but it proves one thing about TracePoint
: Events are triggered before they happen.
Something to keep in mind if you are going to build some sort of tool around this 🙂
Summary
In this post you learned about the TracePoint
class, which allows you to trace a few events like methods calls or new threads. This can be useful as a debugging tool or for code exploration.
Remember to share this post so more people can enjoy it 🙂
This is a useful way . I sometimes want to trace the execution without pry.
Is your gem https://github.com/matugm/visual-call-graph ?
Yes, that’s my gem 🙂
Thanks!
I will check your gem 🙂
Heads up to those trying the
visual_call_graph
gem. It requires graphviz to be installed, which can be downloaded at:https://www.graphviz.org
Thanks for the wonderful gem!
Thanks for reading 🙂
nice one and useful… Thanks
Thank you! I’m glad you found it useful 🙂