diff --git a/README.md b/README.md index 8ca6104..4b9eca7 100644 --- a/README.md +++ b/README.md @@ -361,11 +361,26 @@ request.env['rack.attack.throttle_data'][name] # => { :count => n, :period => p, Rack::Attack uses the [ActiveSupport::Notifications](http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html) API if available. -You can subscribe to 'rack.attack' events and log it, graph it, etc: +You can subscribe to `rack_attack` events and log it, graph it, etc. + +To get notified about specific type of events, subscribe to the event name followed by the `rack_attack` namesapce. +E.g. for throttles use: ```ruby -ActiveSupport::Notifications.subscribe('rack.attack') do |name, start, finish, request_id, payload| - puts payload[:request].inspect +ActiveSupport::Notifications.subscribe("throttle.rack_attack") do |name, start, finish, request_id, payload| + # request object available in payload[:request] + + # Your code here +end +``` + +If you want to subscribe to every `rack_attack` event, use: + +```ruby +ActiveSupport::Notifications.subscribe(/rack_attack/) do |name, start, finish, request_id, payload| + # request object available in payload[:request] + + # Your code here end ``` diff --git a/examples/instrumentation.rb b/examples/instrumentation.rb index 1191a4b..6a22164 100644 --- a/examples/instrumentation.rb +++ b/examples/instrumentation.rb @@ -1,3 +1,3 @@ -ActiveSupport::Notifications.subscribe('rack.attack') do |name, start, finish, request_id, payload| +ActiveSupport::Notifications.subscribe(/rack_attack/) do |name, start, finish, request_id, payload| puts payload[:request].inspect end diff --git a/lib/rack/attack.rb b/lib/rack/attack.rb index c77245e..7eda247 100644 --- a/lib/rack/attack.rb +++ b/lib/rack/attack.rb @@ -88,7 +88,13 @@ class Rack::Attack end def instrument(request) - notifier.instrument('rack.attack', request: request) if notifier + if notifier + event_type = request.env["rack.attack.match_type"] + notifier.instrument("#{event_type}.rack_attack", request: request) + + # Deprecated: Keeping just for backwards compatibility + notifier.instrument("rack.attack", request: request) + end end def cache diff --git a/spec/acceptance/blocking_ip_spec.rb b/spec/acceptance/blocking_ip_spec.rb index cfb2282..102a8fc 100644 --- a/spec/acceptance/blocking_ip_spec.rb +++ b/spec/acceptance/blocking_ip_spec.rb @@ -23,7 +23,7 @@ describe "Blocking an IP" do notified = false notification_type = nil - ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, payload| + ActiveSupport::Notifications.subscribe("blocklist.rack_attack") do |_name, _start, _finish, _id, payload| notified = true notification_type = payload[:request].env["rack.attack.match_type"] end diff --git a/spec/acceptance/blocking_spec.rb b/spec/acceptance/blocking_spec.rb index db176c8..8cd0f63 100644 --- a/spec/acceptance/blocking_spec.rb +++ b/spec/acceptance/blocking_spec.rb @@ -25,7 +25,7 @@ describe "#blocklist" do notification_matched = nil notification_type = nil - ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, payload| + ActiveSupport::Notifications.subscribe("blocklist.rack_attack") do |_name, _start, _finish, _id, payload| notification_matched = payload[:request].env["rack.attack.matched"] notification_type = payload[:request].env["rack.attack.match_type"] end diff --git a/spec/acceptance/blocking_subnet_spec.rb b/spec/acceptance/blocking_subnet_spec.rb index 1f417d7..d608380 100644 --- a/spec/acceptance/blocking_subnet_spec.rb +++ b/spec/acceptance/blocking_subnet_spec.rb @@ -29,7 +29,7 @@ describe "Blocking an IP subnet" do notified = false notification_type = nil - ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, payload| + ActiveSupport::Notifications.subscribe("blocklist.rack_attack") do |_name, _start, _finish, _id, payload| notified = true notification_type = payload[:request].env["rack.attack.match_type"] end diff --git a/spec/acceptance/safelisting_ip_spec.rb b/spec/acceptance/safelisting_ip_spec.rb index bdf7d67..c0b8faf 100644 --- a/spec/acceptance/safelisting_ip_spec.rb +++ b/spec/acceptance/safelisting_ip_spec.rb @@ -38,7 +38,7 @@ describe "Safelist an IP" do it "notifies when the request is safe" do notification_type = nil - ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, payload| + ActiveSupport::Notifications.subscribe("safelist.rack_attack") do |_name, _start, _finish, _id, payload| notification_type = payload[:request].env["rack.attack.match_type"] end diff --git a/spec/acceptance/safelisting_spec.rb b/spec/acceptance/safelisting_spec.rb index dc4d82d..2c4ceb2 100644 --- a/spec/acceptance/safelisting_spec.rb +++ b/spec/acceptance/safelisting_spec.rb @@ -41,7 +41,7 @@ describe "#safelist" do notification_matched = nil notification_type = nil - ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, payload| + ActiveSupport::Notifications.subscribe("safelist.rack_attack") do |_name, _start, _finish, _id, payload| notification_matched = payload[:request].env["rack.attack.matched"] notification_type = payload[:request].env["rack.attack.match_type"] end diff --git a/spec/acceptance/safelisting_subnet_spec.rb b/spec/acceptance/safelisting_subnet_spec.rb index 50d99f6..45c5bf9 100644 --- a/spec/acceptance/safelisting_subnet_spec.rb +++ b/spec/acceptance/safelisting_subnet_spec.rb @@ -38,7 +38,7 @@ describe "Safelisting an IP subnet" do it "notifies when the request is safe" do notification_type = nil - ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, payload| + ActiveSupport::Notifications.subscribe("safelist.rack_attack") do |_name, _start, _finish, _id, payload| notification_type = payload[:request].env["rack.attack.match_type"] end diff --git a/spec/acceptance/throttling_spec.rb b/spec/acceptance/throttling_spec.rb index 719def8..bf3a79b 100644 --- a/spec/acceptance/throttling_spec.rb +++ b/spec/acceptance/throttling_spec.rb @@ -125,7 +125,7 @@ describe "#throttle" do notification_data = nil notification_discriminator = nil - ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, payload| + ActiveSupport::Notifications.subscribe("throttle.rack_attack") do |_name, _start, _finish, _id, payload| notification_matched = payload[:request].env["rack.attack.matched"] notification_type = payload[:request].env["rack.attack.match_type"] notification_data = payload[:request].env['rack.attack.match_data'] diff --git a/spec/acceptance/track_spec.rb b/spec/acceptance/track_spec.rb index 5f72db8..cec3000 100644 --- a/spec/acceptance/track_spec.rb +++ b/spec/acceptance/track_spec.rb @@ -11,7 +11,7 @@ describe "#track" do notification_matched = nil notification_type = nil - ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, payload| + ActiveSupport::Notifications.subscribe("track.rack_attack") do |_name, _start, _finish, _id, payload| notification_matched = payload[:request].env["rack.attack.matched"] notification_type = payload[:request].env["rack.attack.match_type"] end diff --git a/spec/acceptance/track_throttle_spec.rb b/spec/acceptance/track_throttle_spec.rb index 1d2c5ab..bc03555 100644 --- a/spec/acceptance/track_throttle_spec.rb +++ b/spec/acceptance/track_throttle_spec.rb @@ -14,7 +14,7 @@ describe "#track with throttle-ish options" do notification_matched = nil notification_type = nil - ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, payload| + ActiveSupport::Notifications.subscribe("track.rack_attack") do |_name, _start, _finish, _id, payload| notification_matched = payload[:request].env["rack.attack.matched"] notification_type = payload[:request].env["rack.attack.match_type"] end diff --git a/spec/rack_attack_instrumentation_spec.rb b/spec/rack_attack_instrumentation_spec.rb index 898a7d2..5045320 100644 --- a/spec/rack_attack_instrumentation_spec.rb +++ b/spec/rack_attack_instrumentation_spec.rb @@ -7,9 +7,14 @@ if ActiveSupport::VERSION::MAJOR > 3 require_relative 'spec_helper' require 'active_support/subscriber' class CustomSubscriber < ActiveSupport::Subscriber - def rack(event) - # Do virtually (but not) nothing. - event.inspect + @notification_count = 0 + + class << self + attr_accessor :notification_count + end + + def throttle(_event) + self.class.notification_count += 1 end end @@ -23,12 +28,14 @@ if ActiveSupport::VERSION::MAJOR > 3 describe "with throttling" do before do ActiveSupport::Notifications.stub(:notifier, ActiveSupport::Notifications::Fanout.new) do - CustomSubscriber.attach_to("attack") + CustomSubscriber.attach_to("rack_attack") 2.times { get '/', {}, 'REMOTE_ADDR' => '1.2.3.4' } end end + it 'should instrument without error' do last_response.status.must_equal 429 + assert_equal 1, CustomSubscriber.notification_count end end end diff --git a/spec/rack_attack_track_spec.rb b/spec/rack_attack_track_spec.rb index 39c6ab9..7ec4483 100644 --- a/spec/rack_attack_track_spec.rb +++ b/spec/rack_attack_track_spec.rb @@ -35,7 +35,7 @@ describe 'Rack::Attack.track' do # A second track Rack::Attack.track("homepage") { |req| req.path == "/" } - ActiveSupport::Notifications.subscribe("rack.attack") do |*_args| + ActiveSupport::Notifications.subscribe("track.rack_attack") do |*_args| Counter.incr end