{"id":13878903,"url":"https://github.com/st0012/object_tracer","last_synced_at":"2025-09-29T23:31:54.135Z","repository":{"id":41194110,"uuid":"216168252","full_name":"st0012/object_tracer","owner":"st0012","description":"ObjectTracer tracks objects and records their activities","archived":true,"fork":false,"pushed_at":"2024-05-04T12:58:29.000Z","size":1443,"stargazers_count":448,"open_issues_count":5,"forks_count":13,"subscribers_count":13,"default_branch":"master","last_synced_at":"2024-05-18T22:22:36.344Z","etag":null,"topics":["debugging","debugging-tool","object-oriented-tracing","rails","ruby","ruby-on-rails","rubygem","trace","tracepoints","tracing"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/st0012.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-10-19T07:41:15.000Z","updated_at":"2024-06-19T02:49:45.154Z","dependencies_parsed_at":"2024-06-19T02:49:43.164Z","dependency_job_id":"d2e3d653-3545-48de-84ac-fd9c849d69d6","html_url":"https://github.com/st0012/object_tracer","commit_stats":{"total_commits":318,"total_committers":6,"mean_commits":53.0,"dds":"0.018867924528301883","last_synced_commit":"5699c5dda9e962a1b966987921c6bdd1b5e974e4"},"previous_names":["st0012/tapping_device"],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/st0012%2Fobject_tracer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/st0012%2Fobject_tracer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/st0012%2Fobject_tracer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/st0012%2Fobject_tracer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/st0012","download_url":"https://codeload.github.com/st0012/object_tracer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234673584,"owners_count":18869694,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["debugging","debugging-tool","object-oriented-tracing","rails","ruby","ruby-on-rails","rubygem","trace","tracepoints","tracing"],"created_at":"2024-08-06T08:02:03.746Z","updated_at":"2025-09-29T23:31:48.661Z","avatar_url":"https://github.com/st0012.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"\u003e [!WARNING]\n\u003e This gem has been deprecated in favor of [ruby/tracer](https://github.com/ruby/tracer)\n\n# ObjectTracer (previously called TappingDevice)\n\n![GitHub Action](https://github.com/st0012/object_tracer/workflows/Ruby/badge.svg)\n[![Gem Version](https://badge.fury.io/rb/object_tracer.svg)](https://badge.fury.io/rb/object_tracer)\n[![Maintainability](https://api.codeclimate.com/v1/badges/3e3732a6983785bccdbd/maintainability)](https://codeclimate.com/github/st0012/object_tracer/maintainability)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/3e3732a6983785bccdbd/test_coverage)](https://codeclimate.com/github/st0012/object_tracer/test_coverage)\n[![Open Source Helpers](https://www.codetriage.com/st0012/object_tracer/badges/users.svg)](https://www.codetriage.com/st0012/object_tracer)\n\n\n## Introduction\nAs the name states, `ObjectTracer` allows you to secretly listen to different events of an object:\n\n- `Method Calls` - what does the object do\n- `Traces` - how is the object used by the application\n- `State Mutations` - what happens inside the object\n\nAfter collecting the events, `ObjectTracer` will output them in a nice, readable format to either stdout or a file. \n\n**Ultimately, its goal is to let you know all the information you need for debugging with just 1 line of code.**\n\n## Usages\n\n### Track Method Calls\n\nBy tracking an object's method calls, you'll be able to observe the object's behavior very easily\n\n\u003cimg src=\"https://github.com/st0012/object_tracer/blob/master/images/print_calls.png\" alt=\"image of print_calls output\" width=\"50%\"\u003e\n\nEach entry consists of 5 pieces of information:\n- method name\n- source of the method\n- call site\n- arguments\n- return value\n\n![explanation of individual entry](https://github.com/st0012/object_tracer/blob/master/images/print_calls%20-%20single%20entry.png)\n\n#### Helpers\n\n- `print_calls(object)` - prints the result to stdout\n- `write_calls(object, log_file: \"file_name\")` - writes the result to a file\n\t- the default file is `/tmp/object_tracer.log`, but you can change it with `log_file: \"new_path\"` option\n\n#### Use Cases\n- Understand a service object/form object's behavior\n- Debug a messy controller\n\n### Track Traces\n\nBy tracking an object's traces, you'll be able to observe the object's journey in your application\n\n![image of print_traces output](https://github.com/st0012/object_tracer/blob/master/images/print_traces.png)\n\n#### Helpers\n\n- `print_traces(object)` - prints the result to stdout\n- `write_traces(object, log_file: \"file_name\")` - writes the result to a file\n\t- the default file is `/tmp/object_tracer.log`, but you can change it with `log_file: \"new_path\"` option\n\n#### Use Cases\n- Debug argument related issues\n- Understand how a library uses your objects\n\n### Track State Mutations\n\nBy tracking an object's traces, you'll be able to observe the state changes happen inside the object between each method call\n\n\u003cimg src=\"https://github.com/st0012/object_tracer/blob/master/images/print_mutations.png\" alt=\"image of print_mutations output\" width=\"50%\"\u003e\n\n#### Helpers\n\n- `print_mutations(object)` - prints the result to stdout\n- `write_mutations(object, log_file: \"file_name\")` - writes the result to a file\n\t- the default file is `/tmp/object_tracer.log`, but you can change it with `log_file: \"new_path\"` option\n\n#### Use Cases\n- Debug state related issues\n- Debug memoization issues\n\n### Track All Instances Of A Class\n\nIt'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:\n\n- `print_instance_calls(ObjectKlass)`\n- `print_instance_traces(ObjectKlass)`\n- `print_instance_mutations(ObjectKlass)`\n- `write_instance_calls(ObjectKlass)`\n- `write_instance_traces(ObjectKlass)`\n- `write_instance_mutations(ObjectKlass)`\n\n\n### Use `with_HELPER_NAME` for chained method calls\n\nIn Ruby programs, we often chain multiple methods together like this:\n\n```ruby\nSomeService.new(params).perform\n```\n\nAnd to debug it, we'll need to break the method chain into\n\n```ruby\nservice = SomeService.new(params)\nprint_calls(service, options)\nservice.perform\n```\n\nThis kind of code changes are usually annoying, and that's one of the problems I want to solve with `ObjectTracer`.\n\nSo here's another option, just insert a `with_HELPER_NAME` call in between:\n\n```ruby\nSomeService.new(params).with_print_calls(options).perform\n```\n\nAnd it'll behave exactly like\n\n```ruby\nservice = SomeService.new(params)\nprint_calls(service, options)\nservice.perform\n```\n\n## Installation\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'object_tracer', group: :development\n```\n\nAnd then execute:\n\n```\n$ bundle\n```\n\nOr install it directly:\n\n```\n$ gem install object_tracer\n```\n\n**Depending on the size of your application, `ObjectTracer` could harm the performance significantly.  So make sure you don't put it inside the production group**\n\n\n## Advance Usages \u0026 Options \n\n### Add Conditions With `.with`\n\nSometimes 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.\n\n```ruby\n# only prints calls with name matches /foo/\nprint_calls(object).with do |payload|\n  payload.method_name.to_s.match?(/foo/)\nend\n```\n\n### Options\n\nThere are many options you can pass when using a helper method. You can list all available options and their default value with\n\n```ruby\nObjectTracer::Configurable::DEFAULTS #=\u003e {\n  :filter_by_paths=\u003e[], \n  :exclude_by_paths=\u003e[], \n  :with_trace_to=\u003e50, \n  :event_type=\u003e:return, \n  :hijack_attr_methods=\u003efalse, \n  :track_as_records=\u003efalse, \n  :inspect=\u003efalse, \n  :colorize=\u003etrue, \n  :log_file=\u003e\"/tmp/object_tracer.log\"\n}\n```\n\nHere are some commonly used options:\n\n#### `colorize: false` \n\n- default: `true`\n\nBy default `print_calls` and `print_traces` colorize their output. If you don't want the colors, you can use `colorize: false` to disable it.\n\n\n```ruby\nprint_calls(object, colorize: false)\n```\n\n\n#### `inspect: true` \n\n- default: `false`\n\nAs 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:\n\n``` ruby\npost.to_s #=\u003e #\u003cPost:0x00007f89a55201d0\u003e\npost.inspect #=\u003e #\u003cPost id: 649, user_id: 3, topic_id: 600, post_number: 1, raw: \"Hello world\", cooked: \"\u003cp\u003eHello world\u003c/p\u003e\", 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\u003e\n```\n\n#### `hijack_attr_methods: true` \n\n- default: `false`\n\t- except for `tap_mutation!` and `print_mutations`\n\t\nBecause `TracePoint` doesn't track methods generated by `attr_*` helpers (see [this issue](https://bugs.ruby-lang.org/issues/16383) for more info), we need to redefine those methods with the normal method definition. \n\nFor example, it generates\n\n```ruby\ndef name=(val)\n  @name = val\nend\n```\n\nfor\n\n```ruby\nattr_writer :name\n```\n\nThis hack will only be applied to the target instance with `instance_eval`. So other instances of the class remain untouched.\n\nThe default is `false` because\n\n1. 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. \n2. It's still unclear if this hack safe enough for most applications.\n\n\n#### `ignore_private`\n\nSometimes we use many private methods to perform trivial operations, like\n\n```ruby\nclass Operation\n  def extras\n    dig_attribute(\"extras\")\n  end\n\n  private\n\n  def data\n    @data\n  end\n\n  def dig_attribute(attr)\n    data.dig(\"attributes\", attr) \n  end\nend\n```\n\nAnd we may not be interested in those method calls. If that's the case, you can use the `ignore_private` option\n\n```ruby\noperation = Operation.new(params)\nprint_calls(operation, ignore_private: true) #=\u003e only prints the `extras` call\n```\n\n#### `only_private`\n\nThis option does the opposite of the `ignore_private` option does.\n\n\n### Global Configuration\n\nIf you don't want to pass options every time you use a helper, you can use global configuration to change the default values:\n\n```ruby\nObjectTracer.config[:colorize] = false\nObjectTracer.config[:hijack_attr_methods] = true\n```\n\nAnd if you're using Rails, you can put the configs under `config/initializers/object_tracer.rb` like this:\n\n```ruby\nif defined?(ObjectTracer)\n  ObjectTracer.config[:colorize] = false\n  ObjectTracer.config[:hijack_attr_methods] = true\nend\n```\n\n\n### Lower-Level Helpers\n`print_calls` and `print_traces` aren't the only helpers you can get from `ObjectTracer`. They are actually built on top of other helpers, which you can use as well. To know more about them, please check [this page](https://github.com/st0012/object_tracer/wiki/Advance-Usages)\n\n\n### Related Blog Posts\n- [Optimize Your Debugging Process With Object-Oriented Tracing and object_tracer](http://bit.ly/object-oriented-tracing) \n- [Debug Rails issues effectively with object_tracer](https://dev.to/st0012/debug-rails-issues-effectively-with-tappingdevice-c7c)\n- [Want to know more about your Rails app? Tap on your objects!](https://dev.to/st0012/want-to-know-more-about-your-rails-app-tap-on-your-objects-bd3)\n\n\n## Development\nAfter 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.\n\nTo 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](https://rubygems.org).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/st0012/object_tracer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.\n\n## License\n\nThe gem is available as open-source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\n## Code of Conduct\n\nEveryone interacting in the ObjectTracer project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [code of conduct](https://github.com/st0012/object_tracer/blob/master/CODE_OF_CONDUCT.md).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fst0012%2Fobject_tracer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fst0012%2Fobject_tracer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fst0012%2Fobject_tracer/lists"}