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

Error on sinatra tracing after upgrading to 0.52 #1643

Closed
mscrivo opened this issue Aug 10, 2021 · 9 comments
Closed

Error on sinatra tracing after upgrading to 0.52 #1643

mscrivo opened this issue Aug 10, 2021 · 9 comments
Assignees

Comments

@mscrivo
Copy link
Contributor

mscrivo commented Aug 10, 2021

After upgrading from 0.51 to 0.52, we immediately started getting a slew of these errors:

NoMethodError: undefined method `[]' for nil:NilClass (Most recent call first)
File /home/affinity/vendor/bundle/ruby/3.0.0/gems/ddtrace-0.52.0/lib/ddtrace/contrib/sinatra/env.rb line 13 in datadog_span
File /home/affinity/vendor/bundle/ruby/3.0.0/gems/ddtrace-0.52.0/lib/ddtrace/contrib/sinatra/tracer.rb line 122 in block in route_eval
File /home/affinity/vendor/bundle/ruby/3.0.0/gems/ddtrace-0.52.0/lib/ddtrace/tracer.rb line 283 in trace
File /home/affinity/vendor/bundle/ruby/3.0.0/gems/ddtrace-0.52.0/lib/ddtrace/contrib/sinatra/tracer.rb line 105 in route_eval

Still looking into the codepaths and whether we missed updating something that was deprecated, but thought I'd raise it early.

@ivoanjo ivoanjo self-assigned this Aug 11, 2021
@ivoanjo
Copy link
Member

ivoanjo commented Aug 11, 2021

Hey @mscrivo, thanks a lot for the report!

This looks like a regression from #1628, which shipped in 0.52.0 -- confirming your observation that this issue did not happen on 0.51.1.

From the code path being followed, it looks like you're using a modular sinatra app, e.g. one that subclasses Sinatra::Base.

I have a suspicion about where the issue may be coming from. Could you doublecheck if you're registering the Datadog::Contrib::Sinatra::Tracer middleware in Sinatra as shown in the dd-trace-rb documentation?

It should look something like this

class App < Sinatra::Base
  register Datadog::Contrib::Sinatra::Tracer # <--- the middleware

  get '/' do
    'Hello world!'
  end
end

If you're not, you're actually missing out on a few tracing features; here's how my example test app behaves with the trace middleware:

Screen Shot 2021-08-11 at 10 46 01

...and here's how it looks without the middleware:

Screen Shot 2021-08-11 at 10 48 25

Notice the missing path, process id and status code reporting.

The difference between 0.51.1 and 0.52.0 is that 0.51.1 did not break when the middleware was missing (both of those screenshots were taken using 0.51.1), whereas in 0.52.0 the configuration without middleware breaks for me with exactly the same stack trace as you reported.

I'll start working on a PR to restore the previous behavior, but if your issue is indeed the missing middleware, my suggestion is to add it, since that's how you get the best out of the sinatra integration anyway.

ivoanjo added a commit that referenced this issue Aug 11, 2021
…ssing

This fixes a regression introduced in version 0.52.0 by #1628.

When a Sinatra modular application being traced is missing the
`Datadog::Contrib::Sinatra::Tracer` middleware
(as documented in
<https://docs.datadoghq.com/tracing/setup_overview/setup/ruby/#sinatra>),
no Sinatra request span is ever created (only a route span).

Because we didn't properly account for this in `#datadog_span`, the
following `NoMethodError` was triggered:

```
NoMethodError: undefined method `[]' for nil:NilClass
  dd-trace-rb/lib/ddtrace/contrib/sinatra/env.rb:13:in `datadog_span'
  dd-trace-rb/lib/ddtrace/contrib/sinatra/tracer.rb:122:in `block in route_eval'
  dd-trace-rb/lib/ddtrace/tracer.rb:283:in `trace'
  dd-trace-rb/lib/ddtrace/contrib/sinatra/tracer.rb:105:in `route_eval'
  ruby-2.7.4/gems/sinatra-2.1.0/lib/sinatra/base.rb:1013:in `block (2 levels) in route!'
```

I suspect this is the same issue as was reported in #1643.

Because this configuration is actually not desirable -- spans reported
will be missing crucial request information, as discussed in #1643 --
I've also added a warning to hopefully steer users in the right
direction.
@mscrivo
Copy link
Contributor Author

mscrivo commented Aug 11, 2021

Hi @ivoanjo, thanks for the very detailed response!

I checked and it turns out that we are registering the rack middleware but not the sinatra one. So I see process_id, runtime_id etc on the rack spans, but no the sinatra ones. We do have both a sinatra route and request span though. I can definitely try registering the Sinatra middleware and see if that fixes it.

@ivoanjo
Copy link
Member

ivoanjo commented Aug 11, 2021

Let me know if adding the middleware solves it for you!

Indeed in my screenshots above I was using sinatra directly, without the rack integration; As you pointed out, using the rack integration with sinatra does restore some of the metadata that would otherwise be missing.

In the meanwhile I've opened a PR with a fix in #1644 that restores the previous behavior of not breaking whenever the sinatra request span is missing.

@mscrivo
Copy link
Contributor Author

mscrivo commented Aug 11, 2021

That does seem to have done the trick. Though, now I am seeing 3 levels of sinatra spans, whereas before we only had 2 request & route:

image

Is this normal?

@mscrivo
Copy link
Contributor Author

mscrivo commented Aug 11, 2021

Ah we might have 2 sinatra.request spans because we were manually creating our own middleware before 🤦🏼

@mscrivo
Copy link
Contributor Author

mscrivo commented Aug 11, 2021

This is starting to make more sense now, we didn't register the sinatra middleware because we basically had setup our own to do some extra things:

def self.registered(app)
  app.helpers Tracing::Helpers

  app.before do
    TraceResource.set_resource!(matched_route)

    next unless Datadog.tracer.enabled

    @span =
      Datadog.tracer.trace(
        'sinatra.request',
        service: Datadog.configuration[:sinatra][:service_name],
        span_type: Datadog::Ext::HTTP::TEMPLATE,
      )

    @span.set_tag(Datadog::Ext::HTTP::URL, matched_route)
    @span.set_tag(Datadog::Ext::HTTP::METHOD, request.request_method)
  end

  app.after do
    TraceResource.set_resource!(nil)

    next unless Datadog.tracer.enabled

    @span.resource = "#{request.request_method} #{matched_route}"
    @span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, response.status)
    @span.set_error(env['sinatra.error']) if response.server_error?

    finish_time = Time.now.utc
    duration = finish_time - @span.start_time

    # Reject 98% of uninteresting traces
    if ENDPOINTS_TO_REJECT.include?(matched_route) && Random.rand(100) < 97
      @span.context.sampling_priority = Datadog::Ext::Priority::USER_REJECT
    end

    # Always sample long requests.
    if duration > Affinity::Monitoring::Tracing::ALWAYS_SAMPLE_THRESHOLD
      @span.context.sampling_priority = Datadog::Ext::Priority::USER_KEEP
    end

    @span.finish(finish_time)
  end
end

@ivoanjo
Copy link
Member

ivoanjo commented Aug 11, 2021

Interesting, thanks for sharing! The middleware does provide most of that functionality, so enabling it on top of your custom setup would be quite redundant. If you do prefer to keep using the custom setup without the middleware, my fix in #1644 restores the previous behavior.

@mscrivo
Copy link
Contributor Author

mscrivo commented Aug 11, 2021

Interesting, thanks for sharing! The middleware does provide most of that functionality, so enabling it on top of your custom setup would be quite redundant. If you do prefer to keep using the custom setup without the middleware, my fix in #1644 restores the previous behavior.

yeah that's my thought as well .. I'm going to try removing it and using the middleware instead.

@mscrivo
Copy link
Contributor Author

mscrivo commented Sep 14, 2021

Using the DD middleware solved the issue.

@mscrivo mscrivo closed this as completed Sep 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants