[Awesome Ruby Gem] Use object_tracer gem to track objects and record their activities

object_tracer

As the name states, ObjectTracer allows you to secretly listen to different events of an object:

  • Method Calls - what does the object do

  • Traces - how is the object used by the application

  • State Mutations - what happens inside the object

After collecting the events, ObjectTracer will output them in a nice, readable format to either stdout or a file.

Ultimately, its goal is to let you know all the information you need for debugging with just 1 line of code.

Best practice is to use Bullet in development mode or custom mode (staging, profile, etc.). The last thing you want is your clients getting alerts about how lazy you are.

Installation

You can install it as a gem:

1
$ gem install object_tracer

or add it into a Gemfile (Bundler):

1
2
3
4
5
6
7
8
# Gemfile

# Put gems used only for development or testing in the appropriate group in the Gemfile
group :development do
# st0012/object_tracer: ObjectTracer tracks objects and records their activities
# https://github.com/st0012/object_tracer
gem 'object_tracer', '1.0.0'
end

Then, run bundle install.

1
$ bundle install

Usages

Track Method Calls

By tracking an object’s method calls, you’ll be able to observe the object’s behavior very easily

Each entry consists of 5 pieces of information:

  • method name

  • source of the method

  • call site

  • arguments

  • return value

https://github.com/st0012/object_tracer/raw/master/images/print_calls%20-%20single%20entry.png

Helpers

  • print_calls(object) - prints the result to stdout

  • write_calls(object, log_file: “file_name”) - writes the result to a file

the default file is /tmp/object_tracer.log, but you can change it with log_file: “new_path” option

Use Cases

  • Understand a service object/form object’s behavior

  • Debug a messy controller

Track Traces

By tracking an object’s traces, you’ll be able to observe the object’s journey in your application

https://github.com/st0012/object_tracer/blob/master/images/print_traces.png

Helpers

  • print_traces(object) - prints the result to stdout

  • write_traces(object, log_file: “file_name”) - writes the result to a file

the default file is /tmp/object_tracer.log, but you can change it with log_file: “new_path” option

Use Cases

  • Debug argument related issues

  • Understand how a library uses your objects

Track State Mutations

By tracking an object’s traces, you’ll be able to observe the state changes happen inside the object between each method call

https://github.com/st0012/object_tracer/blob/master/images/print_mutations.png

Helpers

  • print_mutations(object) - prints the result to stdout

  • write_mutations(object, log_file: “file_name”) - writes the result to a file

the default file is /tmp/object_tracer.log, but you can change it with log_file: “new_path” option

Use Cases

  • Debug state related issues

  • Debug memoization issues

Track All Instances Of A Class

It’s not always easy to directly access the objects we want to track, especially when they’re managed by a library (e.g. ActiveRecord::Relation). In such cases, you can use these helpers to track the class’s instances:

1
2
3
4
5
6
print_instance_calls(ObjectKlass)
print_instance_traces(ObjectKlass)
print_instance_mutations(ObjectKlass)
write_instance_calls(ObjectKlass)
write_instance_traces(ObjectKlass)
write_instance_mutations(ObjectKlass)

Use with_HELPER_NAME for chained method calls

In Ruby programs, we often chain multiple methods together like this:

1
SomeService.new(params).perform

And to debug it, we’ll need to break the method chain into

1
2
3
service = SomeService.new(params)
print_calls(service, options)
service.perform

This kind of code changes are usually annoying, and that’s one of the problems I want to solve with ObjectTracer.

So here’s another option, just insert a with_HELPER_NAME call in between:

1
SomeService.new(params).with_print_calls(options).perform

And it’ll behave exactly like

1
2
3
service = SomeService.new(params)
print_calls(service, options)
service.perform

Advance Usages & Options

Add Conditions With .with

Sometimes we don’t need to know all the calls or traces of an object; we just want some of them. In those cases, we can chain the helpers with .with to filter the calls/traces.

1
2
3
4
# only prints calls with name matches /foo/
print_calls(object).with do |payload|
payload.method_name.to_s.match?(/foo/)
end

Options

There are many options you can pass when using a helper method. You can list all available options and their default value with

1
2
3
4
5
6
7
8
9
10
11
ObjectTracer::Configurable::DEFAULTS #=> {
:filter_by_paths=>[],
:exclude_by_paths=>[],
:with_trace_to=>50,
:event_type=>:return,
:hijack_attr_methods=>false,
:track_as_records=>false,
:inspect=>false,
:colorize=>true,
:log_file=>"/tmp/object_tracer.log"
}

See Advance Usages & Options - https://github.com/st0012/object_tracer#advance-usages–options to learn more.

References

[1] st0012/object_tracer: ObjectTracer tracks objects and records their activities - https://github.com/st0012/object_tracer

[2] object_tracer | RubyGems.org | your community gem host - https://rubygems.org/gems/object_tracer

[3] Optimize Your Debugging Process With Object-Oriented Tracing and tapping_device - DEV Community - https://dev.to/st0012/optimize-your-debugging-process-with-object-oriented-tracing-and-tappingdevice-39c6

[4] Debug Rails issues effectively with tapping_device - DEV Community - https://dev.to/st0012/debug-rails-issues-effectively-with-tappingdevice-c7c

[5] Want to know more about your Rails app? Tap on your objects! - DEV Community - https://dev.to/st0012/want-to-know-more-about-your-rails-app-tap-on-your-objects-bd3