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

Roda Integration #2368

Merged
merged 47 commits into from
Mar 15, 2023
Merged

Roda Integration #2368

merged 47 commits into from
Mar 15, 2023

Conversation

wantsui
Copy link
Contributor

@wantsui wantsui commented Nov 15, 2022

What does this PR do?

Continues on the great work started by @randy-girard in #718 by working on a Roda Integration that works with dd-trace-rb 1.x .

Code to trigger automatic instrumentation

require "roda"
require "ddtrace"
class SampleApp < Roda
  use Datadog::Tracing::Contrib::Rack::TraceMiddleware
  Datadog.configure do |c|
    c.tracing.instrument :roda, **options
  end
  route do |r|
    r.root do
      r.get do
        'Hello World!'
      end
    end
  end
end

Available Configuration Options

  • enabled
  • service_name

Example trace:

RodaTrace

Motivation

Add support for Roda

Additional Notes

Addressed Notes:

  1. About error statuses:
  • While testing this, it was found that if an application leads to a 500 internal server error due to a thrown error, Roda doesn't have access to the status code. To account for this, I updated this to default to a 500 status code.
  1. What version(s) should be compatible?
  • To be safe, support is up until 3.x. Whenever 4.x comes out, this integration will need to be revisited.
  1. About Rack:
    It is highly recommended to load in Rack through use Datadog::Tracing::Contrib::Rack::TraceMiddleware because Rack handles the context propagation for distributed tracing.

How to test the change?

See Checks ran.

randy-girard and others added 18 commits July 11, 2019 15:33
… instrumentation and move files to correct new contrib paths.
@github-actions github-actions bot added integrations Involves tracing integrations tracing labels Nov 15, 2022
@wantsui wantsui marked this pull request as ready for review December 13, 2022 22:49
@wantsui wantsui requested a review from a team December 13, 2022 22:49
@wantsui wantsui changed the title [DRAFT] Roda Integration for 1.x (continues from #718) Roda Integration for 1.x (continues from #718) Dec 13, 2022
end

def call
instrument(Ext::SPAN_REQUEST) { super }
Copy link
Contributor

Choose a reason for hiding this comment

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

Can move the error handling logic to the caller

          def call
            instrument(Ext::SPAN_REQUEST) do |span|
              super
            rescue => e
              # ... Handle error
            end
          end

So you could be confident yielding in the block without nested begin/rescue.

response = yield span

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It looks like in the Roda code, dispatch can land on one of these methods (seen in this conditional)

Would I need to duplicate the rescue block and handle the error in both since either one of these can handle the dispatch?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As an update to this, I wasn't able to move the error handling logic anywhere else because it interfered with the errors produced by the underlying app.

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.

Looks pretty good! 👍

@marcotc
Copy link
Member

marcotc commented Dec 20, 2022

I update this branch. The errors now look like regular PR test errors.

ivoanjo added a commit that referenced this pull request Jan 24, 2023
**What does this PR do?**:

This PR was extracted from the Roda integration PR (#2368) and includes
**only** the addition of `roda` to the appraisals + the result of running
`bundle exec rake appraisal:install`.

**Motivation**:

I decided to break this from #2368 as fiddling with appraisals has
caused a lot of back-and-forth and lost time on a PR that is otherwise
in good shape.

Let's merge this as fast as possible, and then that PR can focus only
on adding Roda.

**Additional Notes**:

(N/A)

**How to test the change?**:

Roda testing will come as part of #2368. This PR is mostly a no-op, and CI
should still be green.
Copy link
Contributor

@delner delner left a comment

Choose a reason for hiding this comment

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

Looking clean, well organized as I'd expect a good integration to be!

Some minor tweaks on edge cases involving errors/versions worth examining. Please see comments for more details.

Where relevant or useful, I would suggest also adding code comment documentation as it might help an unfamiliar developer wrap their head around instrumentation behavior.

lib/datadog/tracing/contrib/roda/configuration/settings.rb Outdated Show resolved Hide resolved
ensure
begin
response = yield
rescue
Copy link
Contributor

Choose a reason for hiding this comment

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

Generally recommend classifying what kind of error is caught: StandardError if you don't want to trap kill signals, Exception if you want all signals (have be to very careful when catching Exception). StandardError is likely correct here.

To clarify, the purpose here is to add additional tags in case of an error? I think it might be better to provide an on_error argument to the #trace call, as it will handle the exception and what not for you. this way you can eliminate the begin/rescue in the ensure. Bonus is that it will handle Exception for you.

Copy link
Member

Choose a reason for hiding this comment

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

I paired with Wan on this one as well, and the on_error would not fit well for this case because we need the local closure variable request_method in the error handler.

If we extract the error handling to on_error: method(:handle_error), then def handle_error does not have access to request_method.
Alternatively, we could declare it inlince on_error: ->{...} but the method is pretty large.

I think we can keep it as in this file, as the alternatives are less legible.

Copy link
Member

Choose a reason for hiding this comment

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

I paired with Wan on this one as well, and the on_error would not fit well for this case because we need the local closure variable request_method in the error handler.

If we extract the error handling to on_error: method(:handle_error), then def handle_error does not have access to request_method.
Alternatively, we could declare it inlince on_error: ->{...} but the method is pretty large.

I think we can keep it as in this file, as the alternatives are less legible.

# The status code is unknown to Roda and decided by the upstream web runner.
# In this case, spans default to status code 500 rather than a blank status code.
default_error_status = '500'
span.resource = "#{request_method} #{default_error_status}"
Copy link
Contributor

Choose a reason for hiding this comment

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

Possibly strange edge case here where request.request_method.to_s.upcase raised an error, hit the ensure block, request raised an error, caught by this rescue block, then request_method will likely be undefined, possibly raising another error.

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'm not sure how this error can be thrown because all routes should be defined with a type from the start. Do you have a suggestion for handling this scenario?

Copy link
Member

Choose a reason for hiding this comment

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

I paired with Wan and it's not possible for request.request_method.to_s.upcase to fail, as it comes straight from Rack and it's part of the Rack contract. This is the same behaviour of our other Rack-ralated integrations (Sinatra, Rails, Hanami, Grace)

include Contrib::Integration

MINIMUM_VERSION = Gem::Version.new('2.0.0')
MAXIMUM_VERSION = Gem::Version.new('4.0.0')
Copy link
Contributor

Choose a reason for hiding this comment

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

Good to know this maximum. Do we know we don't support Roda 4.0.0? If so, why don't we?

Also "maximum" version as a name is slightly misleading in that its exclusive (we don't actually support 4.0.0.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

At the time of this comment: Roda 4.x isn't out. The latest version is 3.65.0.

Given the changes that occurred between 1.x and 2.x, I'm just being cautious by setting a maximum of 4.x for now. That way, in our public docs, we can be clear that this logic is intended for 2.x and 3.x.

Whenever 4.x comes out, it'll require visiting to make sure it still functions as expected.

@@ -511,6 +512,7 @@ For a list of available integrations, and their configuration options, please re
| Redis | `redis` | `>= 3.2` | `>= 3.2` | *[Link](#redis)* | *[Link](https://github.com/redis/redis-rb)* |
| Resque | `resque` | `>= 1.0` | `>= 1.0` | *[Link](#resque)* | *[Link](https://github.com/resque/resque)* |
| Rest Client | `rest-client` | `>= 1.8` | `>= 1.8` | *[Link](#rest-client)* | *[Link](https://github.com/rest-client/rest-client)* |
| Roda | `roda` | `>= 2.1` | `>= 2.1` | *[Link](#roda)* | *[Link](https://github.com/jeremyevans/roda)* |
Copy link
Contributor

Choose a reason for hiding this comment

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

If there's an upper limit on versions we support, we should add that here as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great catch! I was being cautious by hardcoding a limit of 4.x, so I should update this Getting Started doc too!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the latest commit, this now gives a range ending <4 (since it works with 3.x):

| Roda                       | `roda`                     | `>= 2.1, <4`             | `>= 2.1, <4`              | *[Link](#roda)*                     | *[Link](https://github.com/jeremyevans/roda)*   

# Patcher enables patching of 'roda'
module Patcher
include Contrib::Patcher
::Roda.use Datadog::Tracing::Contrib::Rack::TraceMiddleware if defined? ::Roda
Copy link
Member

Choose a reason for hiding this comment

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

We should remove this top-level call and instead, due to lack of a good way to automatically instrument Roda+Rack, we should add this manual step to the readme.

wantsui added 2 commits March 14, 2023 10:50
…plications wll need to call on it. Tests and GettingStarted have been updated for that change.
@marcotc marcotc changed the title Roda Integration for 1.x (continues from #718) Roda Integration Mar 14, 2023
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, @wantsui! 🙇

@marcotc marcotc merged commit 4e51eae into master Mar 15, 2023
@marcotc marcotc deleted the add-roda-rebase branch March 15, 2023 18:10
@github-actions github-actions bot added this to the 1.11.0 milestone Mar 15, 2023
@lloeki lloeki modified the milestones: 1.11.0, 1.11.0.beta1 Apr 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integrations Involves tracing integrations tracing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants