ActiveSupport::Notifications is a notification system built into the rails. You can subscribe to certain notifications in Rails and call your code when they are sent. This is somewhat similar to ActiveSupport::Callbacks , but they work throughout the project and no events need to be announced in advance.'render' notification: ActiveSupport::Notifications.subscribe("render") do |*args| # render end subscribe method. The subscribe method returns a link to the subscriber, it may be required to unsubscribe from the notification.ActiveSupport::Notifications.publish method: ActiveSupport::Notifications.publish('render', 'arg1', 'arg2') 'render' , 'arg1' and 'arg2' will be transferred to the subscribe block.ActiveSupport::Notifications there is a very useful method instrument . It accepts a block and after which it sends a notification with time stamps of the beginning and end of block execution, as well as a hash with additional data. Rails uses this mechanism, and indirectly, both the subscribe and publish methods to create detailed logs in the development environment (production uses the same “gauges”, but not everything is written to the log) def do_something # end ActiveSupport::Notifications.instrument def do_something ActiveSupport::Notifications.instrument('benchmark.do_something', desc: 'Some description') do # end end config/initializers/benchmarking.rb subscribe to all notifications with the string 'benchmark.' . logger = Logger.new(File.join(Rails.root, 'log', "benchmarks.log")) ActiveSupport::Notifications.subscribe(%r/benchmark\.*/) do |name, start, ending, transaction_id, payload| method = name.split(?.).last duration = (1000.0 * (ending - start)) message = if payload[:exception].present? payload[:exception].join(' ') else payload[:desc].to_s end logger.info("Benchmark:%s: %.0fms - %s" % method, duration, message) end name, start, ending, transaction_id, payload .name - the name of the captured notificationstart - start time of the blockending - block end timetransaction_id - unique id, usually unique within one threadpayload - additional data transferred to the “meter”payload[:exception] will be written with the name of the exception and an error message. This also needs to be taken into account.ActiveSupport::Notifications in logging Rails can be found in more detail in the modules ActiveSupport::LogSubscriber , ActiveRecord::LogSubscriber , ActionController::LogSubscriber and ActionMailer::LogSubscriber . callback = lambda do|*args| # # "event.name" end ActiveSupport::Notifications.subscribed(callback, "event.name") do # end unsubscribe method and pass it a link to the subscriber. ActiveSupport::Notifications.unsubscribe(subscriber) ActiveSupport::Notifications::Fanout , it will also be interesting to look at the ActiveSupport::Notifications::Instrumenter class, which is responsible for measuring the block execution time in the instrument methodActiveSupport::Notifications : class Module def benchmark_it *names options, names = benchmark_options_and_names(*names) names.each do |name| target, punctuation = name.to_s.sub(/([?!=])$/, ''), $1 define_method "#{target}_with_benchmark#{punctuation}" do |*args| ActiveSupport::Notifications.instrument("benchmark.#{self.name}.#{name}", options) do send("#{target}_without_benchmark#{punctuation}", *args) end end alias_method_chain name, :benchmark end end protected def benchmark_options_and_names *args options = args.last.is_a?(Hash) ? args.pop : {} [{desc: ''}.merge(options), args] end end ActiveSupport::Notifications.subscribe(%r/benchmark\.*/) do |name, start, ending, transaction_id, payload| _, classname, method = name.split(?.) duration = (1000.0 * (ending - start)) message = if payload[:exception].present? payload[:exception].join(' ') else payload[:desc].to_s end Rails.logger.info("Benchmark: %s.%s: %.0fms - %s" % classname, method, duration, message) end class MyClass def my_method # - end # benchmark_it :my_method, desc: ' ' end MyORM , and hang the logging task on the MyORM::LogSubscriber class inherited from ActiveSupport::LogSubscriber . The message code responsible for displaying the logs is not spread over the application, but in one place. Well, of course, you need to place the sensors throughout the library. By the way, these same sensors can be used for anything else besides logging.Source: https://habr.com/ru/post/160701/
All Articles