Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ruby/tracer
Outputs a source level execution trace of a Ruby program.
https://github.com/ruby/tracer
ruby
Last synced: 27 days ago
JSON representation
Outputs a source level execution trace of a Ruby program.
- Host: GitHub
- URL: https://github.com/ruby/tracer
- Owner: ruby
- License: bsd-2-clause
- Created: 2018-06-23T04:54:57.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2024-05-04T13:14:39.000Z (6 months ago)
- Last Synced: 2024-09-29T21:01:21.128Z (about 1 month ago)
- Topics: ruby
- Language: Ruby
- Homepage:
- Size: 217 KB
- Stars: 71
- Watchers: 30
- Forks: 10
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.txt
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# Tracer
[![Ruby](https://github.com/ruby/tracer/actions/workflows/main.yml/badge.svg)](https://github.com/ruby/tracer/actions/workflows/main.yml)
[![Gem Version](https://badge.fury.io/rb/tracer.svg)](https://badge.fury.io/rb/tracer)The `tracer` gem provides helpful tracing utilities to help users observe their program's runtime behaviour.
The currently supported tracers are:
- [`ObjectTracer`](#objecttracer)
- [`IvarTracer`](#ivartracer)
- [`CallTracer`](#calltracer)
- [`ExceptionTracer`](#exceptiontracer)
- [`LineTracer`](#linetracer)It also comes with experimental [IRB integration](#irb-integration) to allow quick access from REPL.
## Installation
```shell
$ bundle add tracer --group=development,test
```Or directly add it to your `Gemfile`
```rb
group :development, :test do
gem "tracer"
end
```If bundler is not being used to manage dependencies, install the gem by executing:
```shell
$ gem install tracer
```## Usage
```rb
Tracer.trace(object) { ... } # trace object's activities in the given block
Tracer.trace_call { ... } # trace method calls in the given block
Tracer.trace_exception { ... } # trace exceptions in the given block
```**Example**
```rb
require "tracer"obj = Object.new
def obj.foo
100
enddef bar(obj)
obj.foo
endTracer.trace(obj) { bar(obj) }
#depth:1 # is used as a parameter obj of Object#bar at test.rb:13:in `block in '
#depth:2 # receives .foo at test.rb:10:in `bar'
```### `tracer/helper`
If you want to avoid the `Tracer` namespace, you can do `require "tracer/helper"` instead:
```rb
require "tracer/helper"trace(object) { ... } # trace object's activities in the given block
trace_call { ... } # trace method calls in the given block
trace_exception { ... } # trace exceptions in the given block
```### Tracer Classes
If you want to have more control over individual traces, you can use individual tracer classes:
#### ObjectTracer
```rb
class User
def initialize(name) = (@name = name)def name() = @name
enddef authorized?(user)
user.name == "John"
enduser = User.new("John")
tracer = ObjectTracer.new(user)
tracer.start do
user.name
authorized?(user)
end#depth:3 # receives #name (User#name) at test.rb:14:in `block in '
#depth:3 # is used as a parameter user of Object#authorized? at test.rb:15:in `block in '
#depth:4 # receives #name (User#name) at test.rb:8:in `authorized?'
```#### IvarTracer
> [!Note]
> Ruby 3.0 and below's accessor calls don't trigger TracePoint properly so the result may be inaccurate with those versions.```rb
require "tracer"class Cat
attr_accessor :name
endcat = Cat.new
tracer = IvarTracer.new(cat, :@name)
tracer.start do
cat.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:12
```#### ExceptionTracer
```rb
ExceptionTracer.new.startbegin
raise "boom"
rescue StandardError
nil
end#depth:0 # raised at test.rb:4
#depth:1 # rescued at test.rb:6
```#### CallTracer
```rb
class User
def initialize(name) = (@name = name)def name() = @name
enddef authorized?(user)
user.name == "John"
enduser = User.new("John")
tracer = CallTracer.new
tracer.start do
user.name
authorized?(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:16
```#### LineTracer
```rb
class User
def initialize(name) = (@name = name)def name() = @name
enddef authorized?(user)
user.name == "John"
enduser = User.new("John")
tracer = LineTracer.new
tracer.start do
user.name
authorized?(user)
end#depth:4 at test.rb:14
#depth:4 at test.rb:15
#depth:5 at test.rb:8
```### IRB-integration
Once 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,] `
trace_call Trace method calls in the given expression. Usage: `trace_call `
trace_exception Trace exceptions in the given expression. Usage: `trace_exception `
```**Example**
```rb
# test.rb
require "tracer"obj = Object.new
def obj.foo
100
enddef bar(obj)
obj.foo
endbinding.irb
``````shell
irb(main):001:0> trace obj, bar(obj)
#depth:23 # is used as a parameter obj of Object#bar at (eval):1:in `'
#depth:24 # 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 `'
#depth:24> #.foo at test.rb:10:in `bar'
#depth:24< #.foo #=> 100 at test.rb:10:in `bar'
#depth:23< Object#bar #=> 100 at (eval):1:in `'
=> 100
```## Customization
TBD
## Acknowledgements
A big shout-out to [@ko1](https://github.com/ko1) (Koichi Sasada) for his awesome work on [`ruby/debug`](https://github.com/ruby/debug).
The [tracers in `ruby/debug`](https://github.com/ruby/debug/blob/master/lib/debug/tracer.rb) were an inspiration and laid the groundwork for this project.## Development
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](https://rubygems.org).
## Contributing
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](https://github.com/ruby/tracer/blob/master/CODE_OF_CONDUCT.md).
## License
The gem is available as open source under the terms of the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause).
## Code of Conduct
Everyone interacting in the Ruby::Tracer project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ruby/tracer/blob/master/CODE_OF_CONDUCT.md).