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