Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Mini Profiler patches to be optional in Rails applications #418

Merged
merged 8 commits into from
Mar 11, 2020
Merged

Allow Mini Profiler patches to be optional in Rails applications #418

merged 8 commits into from
Mar 11, 2020

Conversation

OsamaSayegh
Copy link
Collaborator

This PR allows Rails application to use mini profiler without any of the monkey patches that mini profiler ships with, instead mini profiler will rely completely on ActiveSupport::Notifications.

To use the non-patches version in your Rails app, add config.mini_profiler_without_patches = true to your environment configurations file(s).

There will be some differences between the patches and no-patches versions, for example most importantly measuring SQL/actions/render time won't be as accurate, and there won't be a Net::HTTP "step" because there is no official API that we can use to replicate what this patch does https://github.com/MiniProfiler/rack-mini-profiler/blob/master/lib/patches/net_patches.rb.

@codecov-io
Copy link

codecov-io commented Nov 13, 2019

Codecov Report

Merging #418 into master will increase coverage by 0.3%.
The diff coverage is 92.55%.

Impacted file tree graph

@@            Coverage Diff            @@
##           master     #418     +/-   ##
=========================================
+ Coverage   88.23%   88.53%   +0.3%     
=========================================
  Files          21       22      +1     
  Lines        1249     1335     +86     
=========================================
+ Hits         1102     1182     +80     
- Misses        147      153      +6
Impacted Files Coverage Δ
lib/rack-mini-profiler.rb 96.29% <ø> (ø) ⬆️
lib/mini_profiler/timer_struct/sql.rb 85% <100%> (+0.38%) ⬆️
lib/mini_profiler_rails/railtie_methods.rb 100% <100%> (ø)
lib/mini_profiler/timer_struct/request.rb 99% <100%> (+1.98%) ⬆️
lib/mini_profiler/timer_struct/custom.rb 100% <100%> (ø) ⬆️
lib/mini_profiler/profiler.rb 84.31% <44.44%> (-1.04%) ⬇️
lib/patches/sql_patches.rb 73.91% <71.42%> (-1.7%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 056b600...924e42c. Read the comment docs.

@SamSaffron
Copy link
Member

I think we should be a bit more official about this support including changes to the README.md

Our default I think is correct, we much prefer to get rich information vs limited. But we should be transparent about it.

After enable_advanced_debugging_tools

enable_method_patching : Allow mini profiler to patch existing classes with instrumentation to gather accurate statistics, if omitted we will attempt to use library specific hooks which existing in ActiveRecord.

Something like that... Ideally we can also support Sequel here using existing Sequel hooks, perhaps @jeremyevans can help point you at what hooks you can lean on there?

@OsamaSayegh
Copy link
Collaborator Author

Sure, I can add a note about this change in README.md and changelog, however I wanted to point out (and make sure you noticed) that I'm not using the Rack::MiniProfiler.config object to turn on/off the patches; I'm relying on Rails.configuration to turn patches on/off for this reason:

The Rack::MiniProfiler.config object is only available after you do require rack-mini-profiler, and requiring mini profiler loads everything including the patches (because the default is true), so running Rack::MiniProfiler.config.enable_method_patching = false after require would be way too late. As far as I'm aware there is no clean way to reverse/unload patches in ruby? Maybe if we don't want to tie this config option to Rails, we can use an ENV variable to turn patches on/off?

@SamSaffron
Copy link
Member

Tricky business!

One possible idea is to codify this into the require used in the Gemfile.

gem :rack_mini_profiler, require: [ 'rack_mini_profiler/disable_method_patches', 'rack_mini_profiler' ]

The nice thing about this is that it is super clear what is going on and how to move to the "default" way it works if you don't like the money patches.

I am kind of liking this cause it is super explicit about what is going on, and works with straight rack or rails and can easily be documented.

@rafaelfranca what are your thoughts?

@OsamaSayegh
Copy link
Collaborator Author

I really like this idea as well (didn't know require: option could take an array!) so I made this change.

If people want to disable patches and want to have require: false in their gemfile, they can do this:

gem 'rack-mini-profiler', require: ['disable_method_patches']

If they want to disable patches but don't want to require: false mini profiler, they can do this:

gem 'rack-mini-profiler', require: ['disable_method_patches', 'rack-mini-profiler']

And no change is needed for existing users.

@rafaelfranca
Copy link

Having this on gemfile of Rails application is a no-go for me. It is aesthetically unpleasant and still give the message that patching Rails is ok. Even adding a config to disable monkey patch Rails is a no-go to me. It needs to not patch Rails at all by default to be in the Rails Gemfile.

BTW, I don't have a problem with matching Net::HTTP, I just don't want to add by default a gem to Rails applications that can break every time we change private API that are being patched by the gem.

@SamSaffron
Copy link
Member

SamSaffron commented Nov 15, 2019 via email

@rafaelfranca
Copy link

Where are the action view patches? I only saw commented code related to Action View.

@SamSaffron
Copy link
Member

I think this is the sticking point:

https://github.com/MiniProfiler/rack-mini-profiler/blob/master/lib/mini_profiler_rails/railtie.rb#L60-L65

I am glad to redo this thing so our fallback is less rich if we must https://github.com/MiniProfiler/rack-mini-profiler/blob/master/lib/patches/db/activerecord.rb and then by default we have "direct db driver" patches and a fallback of a limited notification.

@rafaelfranca
Copy link

I think both of those methods send notifications through ActiveSupport::Notifications.

@SamSaffron
Copy link
Member

The trouble with the notifications API is that we are building a tree of events, we ideally want a "before" and "after" call so we can cleanly construct a tree. AS notifications only gives us an after call. We can reverse it into the tree with a bit more work, provided we are lucky and times line up.

I did want to spend a bit of time writing a proposal for a more efficient AS notifications API that can handle these use cases better, will hack away at something.

But yeah current API should in theory be somewhat workable, albeit less efficient than the method patching.

@OsamaSayegh
Copy link
Collaborator Author

Ok, sorry for the delay here 😅

I've changed the default here so that Rails is not patched at all, but the DB drivers (e.g. PG) and Net::HTTP are still patched by default. People can opt in Rails patching by requiring the enable_rails_patches file in their Gemfile.

Note I've used ActiveSupport::Notifications.monotonic_subscribe here which is fairly new API in ActiveSupport and hasn't been included in a release yet as far as I know, so this will only work with future versions of Rails.

I've tested this with a brand new Rails app based off Rails master and it worked great (will double test this tomorrow because I've made some small changes while I was writing tests).

@SamSaffron
Copy link
Member

@rafaelfranca thoughts? is this in line with what you were thinking?

@rafaelfranca
Copy link

Yes. Great work on this! I think you will have to deal with monotonic_subscribe given it is not released yet. Maybe check of its existence before calling?

@OsamaSayegh
Copy link
Collaborator Author

Thank you @rafaelfranca! I've updated the PR so that Mini Profiler will fallback to subscribe if monotonic_subscribe is not available.

@OsamaSayegh OsamaSayegh merged commit b15fe68 into MiniProfiler:master Mar 11, 2020
@OsamaSayegh OsamaSayegh deleted the optional-patches branch March 11, 2020 05:45
kbrock added a commit to kbrock/rack-mini-profiler that referenced this pull request Jun 8, 2023
background: MiniProfiler#418

By default, rack mini profiler is expected to use active support notifications

Before
======

Oracle is working as described, but pg and mysql are not.

SqlPatches.sql_patches returns ["pg"] for postgres and does not patch notifications

verification:

After
=====

Like oracle, postgres and mysql are double checking with patch_rails? to determine if the
rails code should be patched.

SqlPatches.sql_patches returns [] for postgres
kbrock added a commit to kbrock/rack-mini-profiler that referenced this pull request Jun 8, 2023
background: MiniProfiler#418

By default, rack mini profiler is expected to use active support notifications

Before
======

Oracle is working as described, but pg and mysql are not.

SqlPatches.sql_patches returns ["pg"] for postgres, patches postgres,
and does not leverage ActiveSupport::Notifications

After
=====

Like oracle, postgres and mysql are double checking with patch_rails? to determine if the
rails code should be patched.

SqlPatches.sql_patches returns [] for postgres
nateberkopec pushed a commit that referenced this pull request Dec 6, 2023
background: #418

By default, rack mini profiler is expected to use active support notifications

Before
======

Oracle is working as described, but pg and mysql are not.

SqlPatches.sql_patches returns ["pg"] for postgres, patches postgres,
and does not leverage ActiveSupport::Notifications

After
=====

Like oracle, postgres and mysql are double checking with patch_rails? to determine if the
rails code should be patched.

SqlPatches.sql_patches returns [] for postgres
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants