Skip to content

Commit

Permalink
support different approaches of patching used by peek-mysql2
Browse files Browse the repository at this point in the history
  • Loading branch information
glaszig committed Jun 24, 2020
1 parent 86f5bc3 commit a56bf17
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 31 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ gem 'rack-mini-profiler', require: ['prepend_net_http_patch']

This conflict happens when a ruby method is patched twice, once using module prepend, and once using method aliasing. See this [ruby issue](https://bugs.ruby-lang.org/issues/11120) for details. The fix is to apply all patches the same way. Mini Profiler by default will apply its patch using method aliasing, but you can change that to module prepend by adding `require: ['prepend_net_http_patch']` to the gem line as shown above.

#### `peek-mysql2` stack level too deep errors

If you use peek-mysql2 with Rails >= 5, you'll need to use this gem spec in your Gemfile:

```ruby
gem 'rack-mini-profiler', require: ['prepend_mysql2_patch', 'rack-mini-profiler']
```

This should not be necessary with Rails < 5 because peek-mysql2 hooks into mysql2 gem in different ways depending on your Rails version.

#### Rails and manual initialization

In case you need to make sure rack_mini_profiler is initialized after all other gems, or you want to execute some code before rack_mini_profiler required:
Expand Down
35 changes: 4 additions & 31 deletions lib/patches/db/mysql2.rb
Original file line number Diff line number Diff line change
@@ -1,34 +1,7 @@
# frozen_string_literal: true

class Mysql2::Result
module MiniProfiler
def each(*args, &blk)
return super unless defined?(@miniprofiler_sql_id)

start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
result = super
elapsed_time = SqlPatches.elapsed_time(start)

@miniprofiler_sql_id.report_reader_duration(elapsed_time)
result
end
end

prepend MiniProfiler
end

class Mysql2::Client
module MiniProfiler
def query(*args, &blk)
return super unless SqlPatches.should_measure?

result, record = SqlPatches.record_sql(args[0]) do
super
end
result.instance_variable_set("@miniprofiler_sql_id", record) if result
result
end
end

prepend MiniProfiler
if defined?(Rack::MINI_PROFILER_PREPEND_MYSQL2_PATCH)
require "patches/db/mysql2/prepend"
else
require "patches/db/mysql2/alias_method"
end
30 changes: 30 additions & 0 deletions lib/patches/db/mysql2/alias_method.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

# The best kind of instrumentation is in the actual db provider, however we don't want to double instrument

class Mysql2::Result
alias_method :each_without_profiling, :each
def each(*args, &blk)
return each_without_profiling(*args, &blk) unless defined?(@miniprofiler_sql_id)

start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
result = each_without_profiling(*args, &blk)
elapsed_time = SqlPatches.elapsed_time(start)

@miniprofiler_sql_id.report_reader_duration(elapsed_time)
result
end
end

class Mysql2::Client
alias_method :query_without_profiling, :query
def query(*args, &blk)
return query_without_profiling(*args, &blk) unless SqlPatches.should_measure?

result, record = SqlPatches.record_sql(args[0]) do
query_without_profiling(*args, &blk)
end
result.instance_variable_set("@miniprofiler_sql_id", record) if result
result
end
end
34 changes: 34 additions & 0 deletions lib/patches/db/mysql2/prepend.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

class Mysql2::Result
module MiniProfiler
def each(*args, &blk)
return super unless defined?(@miniprofiler_sql_id)

start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
result = super
elapsed_time = SqlPatches.elapsed_time(start)

@miniprofiler_sql_id.report_reader_duration(elapsed_time)
result
end
end

prepend MiniProfiler
end

class Mysql2::Client
module MiniProfiler
def query(*args, &blk)
return super unless SqlPatches.should_measure?

result, record = SqlPatches.record_sql(args[0]) do
super
end
result.instance_variable_set("@miniprofiler_sql_id", record) if result
result
end
end

prepend MiniProfiler
end
5 changes: 5 additions & 0 deletions lib/prepend_mysql2_patch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

module Rack
MINI_PROFILER_PREPEND_MYSQL2_PATCH = true
end

0 comments on commit a56bf17

Please sign in to comment.