The tracer gem provides helpful tracing utilities to help users observe their program's runtime behaviour.
The currently supported tracers are:
It also comes with experimental IRB integration to allow quick access from REPL.
$ bundle add tracer --group=development,testOr directly add it to your Gemfile
group:development,:testdogem"tracer"endIf bundler is not being used to manage dependencies, install the gem by executing:
$ gem install tracerTracer.trace(object){ ... }# trace object's activities in the given blockTracer.trace_call{ ... }# trace method calls in the given blockTracer.trace_exception{ ... }# trace exceptions in the given blockExample
require"tracer"obj=Object.newdefobj.foo100enddefbar(obj)obj.fooendTracer.trace(obj){bar(obj)}#depth:1 #<Object:0x000000010903c190> is used as a parameter obj of Object#bar at test.rb:13:in `block in <main>'#depth:2 #<Object:0x000000010903c190> receives .foo at test.rb:10:in `bar'If you want to avoid the Tracer namespace, you can do require "tracer/helper" instead:
require"tracer/helper"trace(object){ ... }# trace object's activities in the given blocktrace_call{ ... }# trace method calls in the given blocktrace_exception{ ... }# trace exceptions in the given blockIf you want to have more control over individual traces, you can use individual tracer classes:
classUserdefinitialize(name)=(@name=name)defname()=@nameenddefauthorized?(user)user.name == "John"enduser=User.new("John")tracer=ObjectTracer.new(user)tracer.startdouser.nameauthorized?(user)end#depth:3 #<User:0x000000010696cad8 @name="John"> receives #name (User#name) at test.rb:14:in `block in <main>'#depth:3 #<User:0x000000010696cad8 @name="John"> is used as a parameter user of Object#authorized? at test.rb:15:in `block in <main>'#depth:4 #<User:0x000000010696cad8 @name="John"> receives #name (User#name) at test.rb:8:in `authorized?'Note
Ruby 3.0 and below's accessor calls don't trigger TracePoint properly so the result may be inaccurate with those versions.
require"tracer"classCatattr_accessor:nameendcat=Cat.newtracer=IvarTracer.new(cat,:@name)tracer.startdocat.name="Kitty"cat.instance_variable_set(:@name,"Ketty")end#depth:3 Cat#name= sets @name = "Kitty" at test.rb:11#depth:3 Kernel#instance_variable_set sets @name = "Ketty" at test.rb:12ExceptionTracer.new.startbeginraise"boom"rescueStandardErrornilend#depth:0 #<RuntimeError: boom> raised at test.rb:4#depth:1 #<RuntimeError: boom> rescued at test.rb:6classUserdefinitialize(name)=(@name=name)defname()=@nameenddefauthorized?(user)user.name == "John"enduser=User.new("John")tracer=CallTracer.newtracer.startdouser.nameauthorized?(user)end#depth:4 > block at test.rb:13#depth:5 > User#name at test.rb:4#depth:5 < User#name #=> "John" at test.rb:4#depth:5 > Object#authorized? at test.rb:7#depth:6 > User#name at test.rb:4#depth:6 < User#name #=> "John" at test.rb:4#depth:6 > String#== at test.rb:8#depth:6 < String#== #=> true at test.rb:8#depth:5 < Object#authorized? #=> true at test.rb:9#depth:4 < block #=> true at test.rb:16classUserdefinitialize(name)=(@name=name)defname()=@nameenddefauthorized?(user)user.name == "John"enduser=User.new("John")tracer=LineTracer.newtracer.startdouser.nameauthorized?(user)end#depth:4 at test.rb:14#depth:4 at test.rb:15#depth:5 at test.rb:8Once required, tracer registers a few IRB commands to help you trace Ruby expressions:
trace Trace the target object (or self) in the given expression. Usage: `trace [target,] <expression>`
trace_call Trace method calls in the given expression. Usage: `trace_call <expression>`
trace_exception Trace exceptions in the given expression. Usage: `trace_exception <expression>`
Example
# test.rbrequire"tracer"obj=Object.newdefobj.foo100enddefbar(obj)obj.fooendbinding.irbirb(main):001:0> trace obj, bar(obj)
#depth:23 #<Object:0x0000000107a86648> is used as a parameter obj of Object#bar at (eval):1:in `<main>'#depth:24 #<Object:0x0000000107a86648> receives .foo at test.rb:10:in `bar'
=> 100
irb(main):002:0> trace_call bar(obj)
#depth:23> Object#bar at (eval):1:in `<main>'#depth:24> #<Object:0x0000000107a86648>.foo at test.rb:10:in `bar'#depth:24< #<Object:0x0000000107a86648>.foo #=> 100 at test.rb:10:in `bar'#depth:23< Object#bar #=> 100 at (eval):1:in `<main>'
=> 100TBD
A big shout-out to @ko1 (Koichi Sasada) for his awesome work on ruby/debug.
The tracers in ruby/debug were an inspiration and laid the groundwork for this project.
After checking out the repo, run bin/setup to install dependencies. Then, run rake test-unit to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/tracer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
The gem is available as open source under the terms of the 2-Clause BSD License.
Everyone interacting in the Ruby::Tracer project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.