I am exploring ActiveSupport::Notifications
, and would like more information about 'instantiation.active_record'
, than just the :record_count
and :class_name
[1]. For example,
ActiveSupport::Notifications.subscribe /instantiation.active_record/ do |*args|
args.status #Database or ActiveRecord return status
args.result #The actual result set returned
args.etc .. #Any other info I can collect on the event
# Additional code ...
end
Can this be done, and if so, how?
Update: Thanks to Tom and Pavel below. Part of the challenge, is that I am building a 3rd party gem, that will analyze all SQL returns of the host app, without requiring the modification of their code. Basically, plug it into the Gemfile, do a bundle, and away you go.
I am considering extending ActiveRecord::Base, and using the method append_info_to_payload, but thus far have neither working in a gem.
As an example, I would like to overwrite the ActiveRecord::Querying find_by_sql() method's payload, to look like this:
payload = {
record_count: result_set.length,
class_name: name,
result_set: result_set
}
In testing, and manually editing my local ActiveRecord gem, this delivers the complete result_set via ActiveSupport::Notifications pub/sub.
Answer: So, the answer is to use the class_eval
method, and overwrite the find_by_sql method in ActiveRecord::Querying:
ActiveRecord::Querying.class_eval do
def find_by_sql(sql, binds = [], preparable: nil, &block)
result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
column_types = result_set.column_types.dup
columns_hash.each_key { |k| column_types.delete k }
message_bus = ActiveSupport::Notifications.instrumenter
payload = {
record_count: result_set.length,
class_name: name,
result_set: result_set
}
message_bus.instrument("instantiation.active_record", payload) do
result_set.map { |record| instantiate(record, column_types, &block) }
end
end
end
I added this to my gem's initializer.rb
file.
Final: I created two pull requests on ActiveRecord, to have the result_set pass forward in the payload for use in ActiveSupport::Notifications: querying.rb and join_dependency.rb.
Can this be done, and if so, how?
I don't think so.
Take a look at this and this - in both cases payload
is a Hash with only record_count
and class_name
options. No extra options than described in the guide.
You can create a custom hook with ::instrument
. You can then define a payload that has status
, result_set
, etc, and define their behavior in the block.
You can find more robust documentation on ::instrument
and ::subscribe
here.
EDIT: I was looking into this more and came across this stack overflow question. It looks like the method append_info_to_payload
is what you are looking for. It has been moved to a private method is Rails 5.
One last edit: If you are feeling brave the notification is used here and here if you want to insert your extra payload directly 😶.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With