Skip to content

Commit

Permalink
Instrument with ActiveSupport::Notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
wagenet committed Aug 4, 2015
1 parent 52fadb7 commit 94a9989
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 33 deletions.
2 changes: 1 addition & 1 deletion .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Metrics/BlockNesting:
# Offense count: 4
# Configuration parameters: CountComments.
Metrics/ClassLength:
Max: 246
Max: 252

# Offense count: 23
Metrics/CyclomaticComplexity:
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Next Release
* [#1047](/~https://github.com/intridea/grape/pull/1047): Adds `given` to DSL::Parameters, allowing for dependent params - [@rnubel](/~https://github.com/rnubel).
* [#1064](/~https://github.com/intridea/grape/pull/1064): Add public `Grape::Exception::ValidationErrors#full_messages` - [@romanlehnert](/~https://github.com/romanlehnert).
* [#1079](/~https://github.com/intridea/grape/pull/1079): Added `stream` method to take advantage of `Rack::Chunked` [@zbelzer](/~https://github.com/zbelzer).
* [#1086](/~https://github.com/ruby-grape/grape/pull/1086): Added ActiveSupport::Notifications instrumentation - [@wagenet](/~https://github.com/wagenet).
* Your contribution here!

#### Fixes
Expand Down
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2628,6 +2628,34 @@ See [StackOverflow #3282655](http://stackoverflow.com/questions/3282655/ruby-on-

## Performance Monitoring

### Active Support Instrumentation

Grape has built-in support for [ActiveSupport::Notifications](http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html) which provides simple hook points to instrument key parts of your application.

The following are currently supported:

#### endpoint_run.grape

The main execution of an endpoint, includes filters and rendering.

* *endpoint* - The endpoint instance

#### endpoint_render.grape

The execution of the main content block of the endpoint.

* *endpoint* - The endpoint instance

#### endpoint_run_filters.grape

* *endpoint* - The endpoint instance
* *filters* - The filters being executed
* *type* - The type of filters (before, before_validation, after_validation, after)

See the [ActiveSupport::Notifications documentation](http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html] for information on how to subscripe to these events.

### Monitoring Products

Grape integrates with NewRelic via the
[newrelic-grape](/~https://github.com/flyerhzm/newrelic-grape) gem, and
with Librato Metrics with the [grape-librato](/~https://github.com/seanmoon/grape-librato) gem.
Expand Down
1 change: 1 addition & 0 deletions lib/grape.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
require 'active_support/core_ext/hash/deep_merge'
require 'active_support/core_ext/hash/except'
require 'active_support/dependencies/autoload'
require 'active_support/notifications'
require 'multi_json'
require 'multi_xml'
require 'virtus'
Expand Down
74 changes: 42 additions & 32 deletions lib/grape/endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,16 @@ def generate_api_method(method_name, &block)
if instance_methods.include?(method_name.to_sym) || instance_methods.include?(method_name.to_s)
fail NameError.new("method #{method_name.inspect} already exists and cannot be used as an unbound method name")
end

define_method(method_name, &block)
method = instance_method(method_name)
remove_method(method_name)
proc { |endpoint_instance| method.bind(endpoint_instance).call }

proc do |endpoint_instance|
ActiveSupport::Notifications.instrument('endpoint_render.grape', endpoint: self) do
method.bind(endpoint_instance).call
end
end
end
end

Expand Down Expand Up @@ -210,47 +216,49 @@ def equals?(e)
protected

def run(env)
@env = env
@header = {}
ActiveSupport::Notifications.instrument('endpoint_run.grape', endpoint: self, env: env) do
@env = env
@header = {}

@request = Grape::Request.new(env)
@params = @request.params
@headers = @request.headers
@request = Grape::Request.new(env)
@params = @request.params
@headers = @request.headers

cookies.read(@request)
cookies.read(@request)

self.class.before_each.call(self) if self.class.before_each
self.class.before_each.call(self) if self.class.before_each

run_filters befores
run_filters befores, :before

run_filters before_validations
run_filters before_validations, :before_validation

# Retrieve validations from this namespace and all parent namespaces.
validation_errors = []
# Retrieve validations from this namespace and all parent namespaces.
validation_errors = []

# require 'pry-byebug'; binding.pry
# require 'pry-byebug'; binding.pry

route_setting(:saved_validations).each do |validator|
begin
validator.validate!(params)
rescue Grape::Exceptions::Validation => e
validation_errors << e
route_setting(:saved_validations).each do |validator|
begin
validator.validate!(params)
rescue Grape::Exceptions::Validation => e
validation_errors << e
end
end
end

if validation_errors.any?
fail Grape::Exceptions::ValidationErrors, errors: validation_errors, headers: header
end
if validation_errors.any?
fail Grape::Exceptions::ValidationErrors, errors: validation_errors, headers: header
end

run_filters after_validations
run_filters after_validations, :after_validation

response_object = @block ? @block.call(self) : nil
run_filters afters
cookies.write(header)
response_object = @block ? @block.call(self) : nil
run_filters afters, :after
cookies.write(header)

# The Body commonly is an Array of Strings, the application instance itself, or a File-like object.
response_object = file || [body || response_object]
[status, header, response_object]
# The Body commonly is an Array of Strings, the application instance itself, or a File-like object.
response_object = file || [body || response_object]
[status, header, response_object]
end
end

def build_middleware
Expand Down Expand Up @@ -305,9 +313,11 @@ def helpers
mod
end

def run_filters(filters)
(filters || []).each do |filter|
instance_eval(&filter)
def run_filters(filters, type=:other)
ActiveSupport::Notifications.instrument("endpoint_run_filters.grape", endpoint: self, filters: filters, type: type) do
(filters || []).each do |filter|
instance_eval(&filter)
end
end
end

Expand Down

0 comments on commit 94a9989

Please sign in to comment.