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

Disambiguate resource names for grape endpoints with shared paths #1279

Merged
merged 4 commits into from
Dec 17, 2020

Conversation

pzaich
Copy link
Contributor

@pzaich pzaich commented Dec 8, 2020

This PR attempts to address ambiguous resource names that tend to create shared APM resources for Grape endpoints (and corresponding rack request spans).

It looks like the original design intended to create resource names similar to rails controller actions. Given Grapes knowledge of http methods, this can lead to ambiguous resource names. Following REST design patterns, we often have shared paths that use separate request methods (e.g. GET /widgets and POST /widgets) that execute separate code paths. The current naming patterns bucket these endpoints into the same APM resource and view.

The PR adds the following:

Screen Shot 2020-12-02 at 3 00 21 PM

* Add Grape route tag for http request method

Tests have been updated to reflect the change as well as document how the path is generated (including a nested example).

…and additional trace metadata

Add full grape paths to fix resource name collisions and additional trace metadata
@pzaich pzaich requested a review from a team December 8, 2020 00:11
@pzaich pzaich changed the title Disambiguate resource names in for grape resources with shared paths Disambiguate resource names for grape endpoints with shared paths Dec 8, 2020
marcotc
marcotc previously approved these changes Dec 8, 2020
Copy link
Member

@marcotc marcotc left a comment

Choose a reason for hiding this comment

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

Thank you so much @pzaich, this PR looks very well flushed out!

I think the additional information captured totally makes sense and I think the new tags added were definitely needed in first place.

Regarding the span#resource change, I like the rich context now captured. I left a few discussion comments in code about a few suggestion for a variation of the resource value: please let me know what you think of those.

@@ -306,7 +327,7 @@
expect(run_span.name).to eq('grape.endpoint_run')
expect(run_span.span_type).to eq('web')
expect(run_span.service).to eq('grape')
expect(run_span.resource).to eq('TestingAPI#hard_failure')
expect(run_span.resource).to eq('TestingAPI GET /base/hard_failure')
Copy link
Member

Choose a reason for hiding this comment

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

What do you think of this resource name? I think it captures the code structure around this endpoint, allowing you unambiguously identify the affected code path, without having distinct parts joined together.
The extended information (HTTP method, full path) are still captured as tags.

Also, please let me know if this does not actually unambiguously identify the endpoint.

Suggested change
expect(run_span.resource).to eq('TestingAPI GET /base/hard_failure')
expect(run_span.resource).to eq('TestingAPI::base#hard_failure')

expect(run_span.name).to eq('grape.endpoint_run')
expect(run_span.span_type).to eq('web')
expect(run_span.service).to eq('grape')
expect(run_span.resource).to eq('TestingAPI GET /nested/widgets')
Copy link
Member

Choose a reason for hiding this comment

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

Similar to the suggestion above, but displaying how it would work for this nested case.

Suggested change
expect(run_span.resource).to eq('TestingAPI GET /nested/widgets')
expect(run_span.resource).to eq('TestingAPI::nested::widgets#get')

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@marcotc Thanks for the thoughtful feedback! Before looking at some of your specific suggestions, I wanted to understand a bit more about your goals for the resource naming pattern. Your naming recommendation appears to follow relatively closely to the Rails tracer which has an additional routing layer.

In my opinion, Grape has much more knowledge of the actual request path structure than a Rails controller does which puts Grape in a category much closer to Sinatra in practice. For that reason, I prefer to structure the naming similar to Sinatra.

Copy link
Member

Choose a reason for hiding this comment

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

I guess the main question here is: would you rather visually identify your traces by the Ruby method that handled them (TestingAPI::nested::widgets#get), or by the HTTP route they took (TestingAPI GET /nested/widgets)?

No information is lost in either case, as all information still collected as tags. But my case here is: how would you like to read these, when looking at an overview page with dozens of results?

In my personal experience (which is definitely anecdotal), I see the HTTP method and path as a lower-level concern when browsing the service page. While seeing TestingAPI::nested::widgets#get would lead me to directly ask: "did our team touch the get method in the widget namespace recently?".

That being said, I do agree that Grape sits in between Sinatra and Rails when it comes to the level of abstraction atop HTTP (Sinatra being lower level, Rails being higher level).

At the end of day, your experience as a current production user of Grape is the strongest signal here. If believe that TestingAPI GET /nested/widgets gives you a more immediate signal to where in the application this request is being handled, I'm more than happy to go with the current implementation.

My suggestion was trying to along the lines of: "Is the proposed representation the cleanest, most immediately identifiable representation we can think of, while ensuring that it uniquely identifies an endpoint?".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I followed up with our internal teams and the overall consensus is that using a path similar to the Sinatra trace would be preferred. In general, the paths are going to be more generic and understandable for stakeholders that are less plugged into the actual Grape architecture (e.g. engineering leadership and SRE) while still being understandable for developers working directly w/ Grape. Therefor, I'd prefer to stick with the current proposed naming pattern.

lib/ddtrace/contrib/grape/endpoint.rb Outdated Show resolved Hide resolved
@marcotc marcotc self-requested a review December 8, 2020 21:21
@marcotc marcotc dismissed their stale review December 8, 2020 21:21

Oops, I "approved" instead of just leaving a comment. Sorry about that.

@marcotc marcotc requested a review from a team December 8, 2020 21:21
@marcotc marcotc added community Was opened by a community member integrations Involves tracing integrations labels Dec 8, 2020
@marcotc
Copy link
Member

marcotc commented Dec 11, 2020

@pzaich, just an FYI: don't mind the Rails-related CI failures. With the recent release of Rails 6.1, some gems became incompatible with each other, and we are working on fixing our CI to address this.

Copy link
Member

@marcotc marcotc left a comment

Choose a reason for hiding this comment

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

@pzaich, thank you for the discussion, and of course the work you put into this PR. 🎉

@pzaich
Copy link
Contributor Author

pzaich commented Dec 11, 2020

Awesome. @marcotc Do you need me to help get the tests passing?

@marcotc
Copy link
Member

marcotc commented Dec 11, 2020

@pzaich at this point no, as we already started working on fixing CI in another branch.

When ready, we'll merge that fix into master and we can update your branch and merge it for you.

@codecov-io
Copy link

Codecov Report

Merging #1279 (932e6f6) into master (9dcdd10) will increase coverage by 0.00%.
The diff coverage is 99.19%.

Impacted file tree graph

@@           Coverage Diff            @@
##           master    #1279    +/-   ##
========================================
  Coverage   97.79%   97.80%            
========================================
  Files         751      751            
  Lines       35557    35668   +111     
========================================
+ Hits        34774    34885   +111     
  Misses        783      783            
Impacted Files Coverage Δ
lib/ddtrace/contrib/grape/endpoint.rb 95.04% <93.75%> (+0.49%) ⬆️
lib/ddtrace/contrib/grape/ext.rb 100.00% <100.00%> (ø)
spec/ddtrace/contrib/grape/tracer_spec.rb 99.76% <100.00%> (+0.06%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9dcdd10...932e6f6. Read the comment docs.

@marcotc marcotc merged commit 036b5cd into DataDog:master Dec 17, 2020
@github-actions github-actions bot added this to the 0.44.0 milestone Dec 17, 2020
@marcotc
Copy link
Member

marcotc commented Jan 6, 2021

Thank you again for your work in this PR, @pzaich. We've just released v0.44.0, which includes these changes. Let us know if you have any feedback with this new version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
community Was opened by a community member integrations Involves tracing integrations
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants