All Projects → st0012 → Tapping_device

st0012 / Tapping_device

Licence: mit
TappingDevice makes objects tell you what they do, so you don't need to track them yourself.

Programming Languages

ruby
36898 projects - #4 most used programming language

Projects that are alternatives of or similar to Tapping device

Dry Rails
The official dry-rb railtie
Stars: ✭ 142 (-52.03%)
Mutual labels:  rails, ruby-on-rails, rubygem
Karafka
Framework for Apache Kafka based Ruby and Rails applications development.
Stars: ✭ 1,223 (+313.18%)
Mutual labels:  rails, ruby-on-rails, rubygem
Matestack Ui Core
Matestack enables you to create sophisticated, reactive UIs in pure Ruby, without touching JavaScript and HTML. You end up writing 50% less code while increasing productivity, maintainability and developer happiness.
Stars: ✭ 469 (+58.45%)
Mutual labels:  rails, ruby-on-rails, rubygem
Bugsnag Ruby
Bugsnag error monitoring & reporting software for rails, sinatra, rack and ruby
Stars: ✭ 211 (-28.72%)
Mutual labels:  rails, debugging, debugging-tool
zipkin-cpp-opentracing
OpenTracing Tracer implementation for Zipkin in C++
Stars: ✭ 46 (-84.46%)
Mutual labels:  tracing, trace
go-sensor
🚀 Go Distributed Tracing & Metrics Sensor for Instana
Stars: ✭ 90 (-69.59%)
Mutual labels:  tracing, trace
ctrace-go
Canonical OpenTracing for GoLang
Stars: ✭ 12 (-95.95%)
Mutual labels:  tracing, trace
Mediator
Cross-platform GUI gRPC debugging proxy
Stars: ✭ 36 (-87.84%)
Mutual labels:  debugging, debugging-tool
modular routes
Dedicated controllers for each of your Rails route actions.
Stars: ✭ 45 (-84.8%)
Mutual labels:  rubygem, ruby-on-rails
pydbg
Python implementation of the Rust `dbg` macro
Stars: ✭ 85 (-71.28%)
Mutual labels:  debugging, debugging-tool
guide-charles-proxy
Charles - Web Debugging Proxy Application. I want to share my experiences when I worked with Charles. It is such an amazing application for debugging and testing the presentation of UI when trying different set of data. Hope you guys will master Charles after reading this section. Let’s find out! 🖍
Stars: ✭ 22 (-92.57%)
Mutual labels:  debugging, debugging-tool
docker-pudb
Debug Python code within a Docker container remotely from your terminal using pudb
Stars: ✭ 18 (-93.92%)
Mutual labels:  debugging, debugging-tool
elixir-fire-brigade-workshop
Workshop "Join the Elixir Fire Brigade - Level-up Your Elixir Debugging Skills" (ElixirConf US 2017)
Stars: ✭ 14 (-95.27%)
Mutual labels:  debugging, tracing
devmod
Developer Module for debugging web applications
Stars: ✭ 16 (-94.59%)
Mutual labels:  debugging, debugging-tool
iopipe-go
Go agent for AWS Lambda metrics, tracing, profiling & analytics
Stars: ✭ 18 (-93.92%)
Mutual labels:  debugging, tracing
madbomber
Backtrace-on-throw C++ exception logger
Stars: ✭ 17 (-94.26%)
Mutual labels:  debugging, debugging-tool
Kickoff tailwind
A rapid Rails 6 application template for personal use bundled with Tailwind CSS
Stars: ✭ 287 (-3.04%)
Mutual labels:  rails, ruby-on-rails
jquery-manager
Manage jQuery and jQuery Migrate on a WordPress website, activate a specific jQuery and/or jQuery Migrate version. The ultimate jQuery debugging tool for WordPress
Stars: ✭ 27 (-90.88%)
Mutual labels:  debugging, debugging-tool
node-wasm-trace
Instruments wasm files and traces execution
Stars: ✭ 24 (-91.89%)
Mutual labels:  debugging, trace
Watchpoints
watchpoints is an easy-to-use, intuitive variable/object monitor tool for python that behaves similar to watchpoints in gdb.
Stars: ✭ 261 (-11.82%)
Mutual labels:  debugging, debugging-tool

TappingDevice

GitHub Action Gem Version Maintainability Test Coverage Open Source Helpers

Introduction

As the name states, TappingDevice 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, TappingDevice 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.

Usages

Track Method Calls

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

image of print_calls output

Each entry consists of 5 pieces of information:

  • method name
  • source of the method
  • call site
  • arguments
  • return value

explanation of individual entry

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/tapping_device.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

image of print_traces output

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/tapping_device.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

image of print_mutations output

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/tapping_device.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:

  • 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:

SomeService.new(params).perform

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

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 TappingDevice.

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

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

And it'll behave exactly like

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

Installation

Add this line to your application's Gemfile:

gem 'tapping_device', group: :development

And then execute:

$ bundle

Or install it directly:

$ gem install tapping_device

Depending on the size of your application, TappingDevice could harm the performance significantly. So make sure you don't put it inside the production group

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.

# 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

TappingDevice::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/tapping_device.log"
}

Here are some commonly used options:

colorize: false

  • default: true

By default print_calls and print_traces colorize their output. If you don't want the colors, you can use colorize: false to disable it.

print_calls(object, colorize: false)

inspect: true

  • default: false

As you might have noticed, all the objects are converted into strings with #to_s instead of #inspect. This is because when used on some Rails objects, #inspect can generate a significantly larger string than #to_s. For example:

post.to_s #=> #<Post:0x00007f89a55201d0>
post.inspect #=> #<Post id: 649, user_id: 3, topic_id: 600, post_number: 1, raw: "Hello world", cooked: "<p>Hello world</p>", created_at: "2020-05-24 08:07:29", updated_at: "2020-05-24 08:07:29", reply_to_post_number: nil, reply_count: 0, quote_count: 0, deleted_at: nil, off_topic_count: 0, like_count: 0, incoming_link_count: 0, bookmark_count: 0, score: nil, reads: 0, post_type: 1, sort_order: 1, last_editor_id: 3, hidden: false, hidden_reason_id: nil, notify_moderators_count: 0, spam_count: 0, illegal_count: 0, inappropriate_count: 0, last_version_at: "2020-05-24 08:07:29", user_deleted: false, reply_to_user_id: nil, percent_rank: 1.0, notify_user_count: 0, like_score: 0, deleted_by_id: nil, edit_reason: nil, word_count: 2, version: 1, cook_method: 1, wiki: false, baked_at: "2020-05-24 08:07:29", baked_version: 2, hidden_at: nil, self_edits: 0, reply_quoted: false, via_email: false, raw_email: nil, public_version: 1, action_code: nil, image_url: nil, locked_by_id: nil, image_upload_id: nil>

hijack_attr_methods: true

  • default: false
    • except for tap_mutation! and print_mutations

Because TracePoint doesn't track methods generated by attr_* helpers (see this issue for more info), we need to redefine those methods with the normal method definition.

For example, it generates

def name=(val)
  @name = val
end

for

attr_writer :name

This hack will only be applied to the target instance with instance_eval. So other instances of the class remain untouched.

The default is false because

  1. Checking what methods are generated by attr_* helpers isn't free. It's an O(n) operation, where n is the number of methods the target object has.
  2. It's still unclear if this hack safe enough for most applications.

ignore_private

Sometimes we use many private methods to perform trivial operations, like

class Operation
  def extras
    dig_attribute("extras")
  end

  private

  def data
    @data
  end

  def dig_attribute(attr)
    data.dig("attributes", attr) 
  end
end

And we may not be interested in those method calls. If that's the case, you can use the ignore_private option

operation = Operation.new(params)
print_calls(operation, ignore_private: true) #=> only prints the `extras` call

only_private

This option does the opposite of the ignore_private option does.

Global Configuration

If you don't want to pass options every time you use a helper, you can use global configuration to change the default values:

TappingDevice.config[:colorize] = false
TappingDevice.config[:hijack_attr_methods] = true

And if you're using Rails, you can put the configs under config/initializers/tapping_device.rb like this:

if defined?(TappingDevice)
  TappingDevice.config[:colorize] = false
  TappingDevice.config[:hijack_attr_methods] = true
end

Lower-Level Helpers

print_calls and print_traces aren't the only helpers you can get from TappingDevice. They are actually built on top of other helpers, which you can use as well. To know more about them, please check this page

Related Blog Posts

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec 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 tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/st0012/tapping_device. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open-source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the TappingDevice project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the code of conduct.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].