New gem for tracing Active Record queries

Presenting a new gem for tracing Active Record, I wish existed earlier - GitHub - fatkodima/active_record_tracer: A tracer for Active Record queries

Many times I crafted code to get similar reports like in the gem - to profile slow tests, rake tasks, controllers, jobs, find the most popular queries or the most loaded records, N+1s, the lines producing the most queries/records etc.

I hope you will find it useful too.

Sample usage:

 report = ActiveRecordTracer.report do
   # run your code here
 end

 report.pretty_print

Sample output:

 Total runtime: 181.36s
 Total SQL queries: 8936
 Total loaded records: 2648

 Top SQL queries
 -----------------------------------
      857  SAVEPOINT active_record_1

      856  RELEASE SAVEPOINT active_record_1

      382  SELECT "user_roles".* FROM "user_roles" WHERE "user_roles"."id" = $1 LIMIT $2

      362  SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT $2

      301  INSERT INTO "accounts" ("username", "domain", "private_key") VALUES ($1, $2, $3) RETURNING "id"

      219  SELECT "settings".* FROM "settings" WHERE "settings"."thing_type" IS NULL AND "settings"."thing_id" IS NULL AND "settings"."var" = $1 LIMIT $2

      217  INSERT INTO "conversations" ("uri", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"

      201  SELECT "statuses".* FROM "statuses" WHERE "statuses"."deleted_at" IS NULL AND "statuses"."id" = $1 ORDER BY "statuses"."id" DESC LIMIT $2

      175  BEGIN

      174  ROLLBACK

      169  SELECT "account_stats".* = $1 LIMIT $2

      158  SELECT 1 AS one FROM "instances" WHERE "instances"."domain" = $1 LIMIT $2

      155  SELECT 1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2

      152  SELECT "domain_blocks".* FROM "domain_blocks" WHERE "domain_blocks"."domain" IN ($1, $2) ORDER BY CHAR_LENGTH(domain) DESC LIMIT $3
 ...

 SQL queries by location
 -----------------------------------
      586  app/validators/unique_username_validator.rb:12
      391  app/models/user_role.rb:112
      314  app/models/concerns/account/counters.rb:54
      253  app/models/concerns/account/interactions.rb:116
      217  app/models/setting.rb:80
      215  app/models/concerns/status/safe_reblog_insert.rb:19
      168  app/models/concerns/account/counters.rb:48
      165  app/models/domain_block.rb:73
      158  app/models/concerns/domain_materializable.rb:13
      140  app/models/email_domain_block.rb:61
      137  app/models/concerns/database_view_record.rb:8
      123  app/lib/activitypub/activity/create.rb:86
      122  app/lib/activitypub/tag_manager.rb:185
      120  app/models/status.rb:400
      110  app/models/account.rb:375
       98  app/models/concerns/account/finder_concern.rb:32
       98  app/models/concerns/account/finder_concern.rb:16
       87  app/models/status.rb:377
       78  app/models/status.rb:289
       74  app/models/account.rb:150
       68  app/models/follow_request.rb:38
       64  app/services/activitypub/fetch_featured_collection_service.rb:76
       63  app/services/activitypub/process_status_update_service.rb:163
       63  app/models/account.rb:265
       62  app/models/status.rb:371
 ...

 SQL queries by file
 -----------------------------------
      586  app/validators/unique_username_validator.rb
      563  app/models/concerns/account/counters.rb
      495  app/models/status.rb
      392  app/models/user_role.rb
      376  app/models/concerns/account/interactions.rb
      340  app/models/account.rb
      337  app/services/activitypub/process_status_update_service.rb
      241  app/models/setting.rb
      217  app/models/concerns/status/safe_reblog_insert.rb
      213  app/lib/activitypub/activity/create.rb
      196  app/models/concerns/account/finder_concern.rb
      166  app/services/fan_out_on_write_service.rb
      165  app/models/domain_block.rb
      158  app/models/concerns/domain_materializable.rb
      155  app/models/email_domain_block.rb
      137  app/models/concerns/database_view_record.rb
      134  app/lib/activitypub/tag_manager.rb
      107  app/models/follow_request.rb
      106  app/lib/feed_manager.rb
 ...

 SQL queries by backtrace
 -----------------------------------
      539  app/validators/unique_username_validator.rb:12:in `validate'

      306  app/models/user_role.rb:112:in `everyone'
           app/models/user.rb:160:in `role'
           app/models/user.rb:486:in `sanitize_role'

      168  app/models/concerns/account/interactions.rb:116:in `follow!'

      140  app/models/email_domain_block.rb:61:in `blocking?'
           app/models/email_domain_block.rb:49:in `match?'
           app/models/email_domain_block.rb:94:in `requires_approval?'
           app/models/user.rb:470:in `sign_up_email_requires_approval?'
           app/models/user.rb:416:in `set_approved'

      137  app/models/concerns/domain_materializable.rb:13:in `refresh_instances_view'

      124  app/models/concerns/account/counters.rb:54:in `updated_account_stat'
           app/models/concerns/account/counters.rb:38:in `update_count!'
           app/models/concerns/account/counters.rb:24:in `increment_count!'
           app/models/status.rb:455:in `increment_counter_caches'
 ...

 Loaded records by model
 -----------------------------------
      533  Account
      390  UserRole
      287  Status
      101  AccountStat
       70  Setting
       64  User
       29  Follow
       24  AccountDeletionRequest
       21  MediaAttachment
       20  Conversation
       17  FollowRequest
       17  Tag
 ...

 Loaded records by location
 -----------------------------------
      381  app/models/user_role.rb:112
       98  app/models/concerns/account/finder_concern.rb:16
       65  app/models/concerns/account/finder_concern.rb:32
       64  app/models/setting.rb:80
       61  app/models/concerns/account/counters.rb:48
       53  app/lib/activitypub/tag_manager.rb:185
       46  app/models/concerns/rate_limitable.rb:23
       45  app/workers/distribution_worker.rb:10
       45  app/services/fan_out_on_write_service.rb:14
 ...

 Loaded records by file
 -----------------------------------
      385  app/models/user_role.rb
      163  app/models/concerns/account/finder_concern.rb
       97  app/models/concerns/account/counters.rb
       70  app/models/setting.rb
       68  app/models/account.rb
       57  app/services/fan_out_on_write_service.rb
       53  app/lib/activitypub/tag_manager.rb
 ...

 Loaded records by backtrace
 -----------------------------------
      298  app/models/user_role.rb:112:in `everyone'
           app/models/user.rb:160:in `role'
           app/models/user.rb:486:in `sanitize_role'

       61  app/models/setting.rb:80:in `block in []'
           app/models/setting.rb:79:in `[]'
           app/models/setting.rb:65:in `method_missing'
           app/models/user.rb:474:in `open_registrations?'
           app/models/user.rb:419:in `set_approved'

       45  app/services/fan_out_on_write_service.rb:14:in `call'
           app/workers/distribution_worker.rb:10:in `block in perform'
           app/models/concerns/lockable.rb:12:in `block (2 levels) in with_redis_lock'
           app/models/concerns/lockable.rb:10:in `block in with_redis_lock'
           app/lib/redis_configuration.rb:10:in `with'
 ...
5 Likes

This is pretty cool, thank you!

1 Like