No commit activity in last 3 years
No release in over 3 years
A convenient way to process ActiveSupport notifications together with the call stack.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 0.10
~> 10.0
~> 3.0

Runtime

< 5.1, >= 4.0
 Project Readme

NotificationTracer

A convenient way to process ActiveSupport notifications together with the call stack.

Installation

Add gem 'notification_tracer' to your Gemfile.

Usage

The ActiveSupport::Notifications API allows a consumer to subscribe to specific notification events that match a provided pattern. The NotificationTracer::Subscriber wraps and streamlines this process, passing matching event data to a callback:

subscriber = NotificationTracer::Subscriber.new(
   pattern: 'matches.notification',
  callback: ->(**opts){ puts opts.inspect }
)

:pattern can be either a String (exact matching) or a Regexp (pattern matching).

:callback must respond to .call with the following options:

  • :stack ==> the cleaned Ruby callstack
  • :payload ==> an event-specific data hash
  • :duration ==> how long the event took
  • :event_id ==> a unique id for this event
  • :event_name ==> the full name of the event

Subscriber initialization also takes an optional parameter, :cleaner, for scrubbing the callstack. It is recommended to use an instance of ActiveSupport::BacktraceCleaner but any object with a clean :: Array -> Array method is acceptable.

You must explicitly call .subscribe on the Subscriber in order to start receiving events:

:005 > subscriber.subscribed?
=> false 
:006 > subscriber.subscribe
=> #<NotificationTracer::Subscriber:0x007fb03b8b8628 @pattern="matches.notification", @callback=#<Proc:0x007fb03b8b8740@(irb):3 (lambda)>, @real_subscriber=#<ActiveSupport::Notifications::Fanout::Subscribers::Timed:0x007fb03b8836a8 ...> 
:007 > subscriber.subscribed?
=> true 
:008 > 10.times.each{ subscriber.subscribe } # no harm to recall subscribe
=> 10 
:009 > subscriber.subscribed?
=> true 
:010 > subscriber.unsubscribe
=> #<NotificationTracer::Subscriber:0x007fb03b8b8628 @pattern="matches.notification", @callback=#<Proc:0x007fb03b8b8740@(irb):3 (lambda)>, @real_subscriber=nil, ...> 
:011 > subscriber.subscribed?
=> false 

Rails Specific

NotificationTracer::RailsSql provides out-of-the-box logging of sql.active_record events:

tracer = NotificationTracer::RailsSql.new(
  matcher: <a callable that takes a sql string and returns true or false>,
  formatter: <a callable that merges :stack, :sql, :duration, and :uuid into a single output>,
  logger: <a callable that records the output of the formatter>,
  lines: <limits the stack trace to the first N lines, or nil for no limit>,
  silence_rails_code: <true or false, includes framework code in the stack trace>
)
tracer.start # subscribes & enables logging
tracer.pause # disables logging
tracer.stop  # unsubscribes & disables logging

An example :formatter can be found in NotificationTracer::SqlFormatter. This implementation converts the SQL event data into a String suitable for a text logger. It takes an optional parameter, :prefix, which prepends a given String to all messages.

For convenience, NotificationTracer.rails_sql creates a RailsSql instance with a SqlFormatter formatter:

log_users_sql = NotificationTracer.rails_sql(
  prefix: 'DEBUG 2847428',
  logger: ->(msg){ Rails.logger.debug(msg) },
  matcher: ->(sql){ sql =~ /users/ }
); log_users_sql.start

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/fledman/notification_tracer.

License

The gem is available as open source under the terms of the MIT License.