Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[grape] add Grape integration for API endpoints #117

Merged
merged 16 commits into from
Apr 21, 2017
Merged

Conversation

palazzem
Copy link
Contributor

@palazzem palazzem commented Apr 21, 2017

What it does

Add Grape auto instrumentation using the Patcher method. Grape classes are patched so that new instrumentation is available before the task is executed. It requires ActiveSupport and relies on Grape signals to:

  • trace the whole endpoint execution
  • trace before and after filters
  • trace the Endpoint body

This auto instrumentation works standalone, or using the Rack and/or Rails auto instrumentation. If Rails is used, both Rack and Grape integrations are activated.

What's missing

  • documentation
  • integration test and instrumentation for Rails

@palazzem palazzem added the integrations Involves tracing integrations label Apr 21, 2017
@palazzem palazzem added this to the 0.7.0 milestone Apr 21, 2017
@palazzem palazzem requested a review from ufoot April 21, 2017 08:47
Copy link
Member

@ufoot ufoot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks really good at this stage, waiting for you final signal for definitive review, but 👍

return if Thread.current[KEY_RUN]

# retrieve the tracer from the PIN object
pin = Datadog::Pin.get_from(::Grape)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing it this way limits us to "one Grape service per process" as this is shared app wide AFAIK. We can live with it, but it's worth noting. I suspect in most cases it's OK, several apps running on the same server could still override the default with their own respective services names, and after all, it looks like Grape is like this by design.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You usually have one Grape for each application (and so process). If this is not true, it means that you're mounting 2 different Grape applications in the same application. If we want to support that, it means that we should even support having 2 Rails applications running together in the same process.

The major issue, is that supporting this is not so easy. We don't have instances here and adding PIN references in all endpoints and subscribers is quite complex I think.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, not worth the complexity of attaching the PIN to instances, I'm just saying -> let's keep aware we have this limitation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, considering that the standard case is having one Grape application with namespaces. We still not cover some corner case by the way.

# Endpoint module includes a list of subscribers to create
# traces when a Grape endpoint is hit
module Endpoint
KEY_RUN = 'datadog_grape_endpoint_run'.freeze
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for using consts here instead of copy/pasting the keys. Adds a lookup for humans reading the code but much more typo safe OTOH.

span.start_time = start
span.set_tag('grape.route.endpoint', api_view)
span.set_tag('grape.route.path', path)
span.finish_at(finish)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is globally fine. I'm nitpicking but would still probably harden it like in https://github.com/DataDog/dd-trace-rb/blob/master/lib/ddtrace/contrib/rails/action_controller.rb#L71 by adding an ensure clause around start_time = start and finish. Just, to make sure it makes its way down the pipeline. The heuristic I use here is quite dumb -> if there are at least 10 lines of code, however simple they mike look, the probability it yields an exception "some day in the future" is high.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely! forgot to add this enforcing, thanks!

span.set_error(payload[:exception_object]) unless payload[:exception_object].nil?

span.set_tag('grape.filter.type', type.to_s)
span.start_time = start
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, ensure.

module_function

def patch
if !@patched && defined?(::Grape)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for using that patcher pattern, 👍

end

def unpatch
# TODO: implement this (revert aliasing)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

;)

require 'ddtrace/contrib/redis/patcher'
require 'ddtrace/contrib/http/patcher'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was there an issue with the order? (just curious, I'm not requiring any change here)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh no, it's just cosmetic :D

sleep(0.01)
end

desc 'Returns an error'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that really the right comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope ahah

Copy link
Member

@ufoot ufoot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Waiting for CI, but else, LGTM.

assert_equal(false, Datadog::Contrib::ActiveRecord::Patcher.patched?)
assert_equal({ elasticsearch: true, http: true, redis: true, active_record: false }, Datadog::Monkey.get_patched_modules())
assert_equal({ elasticsearch: true, http: true, redis: true, grape: true, active_record: false }, Datadog::Monkey.get_patched_modules())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't run the tests for Grape with old Ruby versions, but I would assume this global monkey patching test is run with oldies such as 1.9. So I'm wondering if we should keep this and just drop it, probably removing the require 'grape' in this test would be enough. Let's wait for the CI advice, what I'm saying is: for a first release, if Grape does not work with 1.9, let's save this for later and choose whatever path makes it straight to the release, we don't want to delay 0.7.0 for such a corner case. If all tests pass -> forget this remark.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@palazzem palazzem merged commit c26b009 into master Apr 21, 2017
@palazzem palazzem deleted the palazzem/rails-grape branch April 21, 2017 15:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integrations Involves tracing integrations
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants