dd-trace-rb
dd-trace-rb copied to clipboard
Sinatra: Tracing differences between 0.54 and 1.0
Hi there, I'm trying to upgrade our app to use 1.0 and running into some differences in behavior between the old and new versions and am just unsure if I'm doing something wrong, or these are intentional. Here's a before and after trace of the same sinatra request:
before:
after:
It no longer seems to be picking up the rack & sinatra services in the same way.
Here's a before and after of our config setup:
before:
Datadog.configure do |c|
c.tracer.enabled = TRACING_ENABLED
c.tracer.hostname = <host>
c.tracer.port = 8126
c.tracer.partial_flush.enabled = ENABLE_PARTIAL_FLUSH
c.tracer sampler:
Datadog::PrioritySampler.new(
post_sampler:
Datadog::Sampling::RuleSampler.new(
[
Datadog::Sampling::SimpleRule.new(sample_rate: SAMPLE_RATE)
]
)
)
c.runtime_metrics.enabled = true
end
after:
Datadog.configure do |c|
c.tracing.enabled = TRACING_ENABLED
c.agent.host = <host>
c.agent.port = 8126
c.tracing.partial_flush.enabled = ENABLE_PARTIAL_FLUSH
c.tracing.sampler =
Datadog::Tracing::Sampling::PrioritySampler.new(
post_sampler:
Datadog::Tracing::Sampling::RuleSampler.new(
[
# Sample all traces at configured SAMPLE_RATE
Datadog::Tracing::Sampling::SimpleRule.new(sample_rate: SAMPLE_RATE)
]
)
)
c.tracing.analytics.enabled = true
c.runtime_metrics.enabled = true
end
We also have the DD annotations setup on our containers like this:
labels:
tags.datadoghq.com/env="<env>"
tags.datadoghq.com/service="web"
tags.datadoghq.com/version="<commit hash>"
we are also calling: use Datadog::Contrib::Rack::TraceMiddleware
in our rack config and register Datadog::Contrib::Sinatra::Tracer
in our Sinatra base classes.
What's interesting is that with version 0.54, it seemingly ignored the service annotation on the container and used the services it auto discovered, so in our case "sinatra", but now it's using "web" as defined in the annotation.
Any help you can provide on what's wrong with our setup after moving to 1.0 would be greatly appreciated. It seems the tracing produced with 0.54 was more "correct", so I'm hoping I'm just misconfiguring something in 1.0
👋 @mscrivo, could try removing register Datadog::Contrib::Sinatra::Tracer
and checking if the traces are more legible for your application? I see we still have it documented to manually register the Sinatra integration, but we already register ddtrace
into Sinatra at configuration time, thus shouldn't be needed: https://github.com/DataDog/dd-trace-rb/blob/2703f941734253fa864d5d4e29903f86f4085f5a/lib/datadog/tracing/contrib/sinatra/patcher.rb#L61-L62
The combination of Rack and Sinatra spans into the same service is expected and desirable here. service_name
is meant to reflect the name of the application, not layers within the application. We incorrectly separated spans of the same service into different service names before 1.0, and this addresses that issue.
However, seconding what @marcotc said, I think the real concern is the duplication of Rack spans. That shouldn't happen. I would guess there should only be one Rack span, so I would want to determine why there are multiple now. Is instrumentation injected incorrectly?
A few things might be of interest:
- Do the Rack spans all look the same?
- What does the stack trace look like once you enter the
sinatra.request
? - How are you activating instrumentation? (With
require 'ddtrace/autoinstrument'
?)
That may give us some hints. Beyond that, it would be helpful if we can determine some steps to replicate this on our end. Is it as simple as setting up a Sinatra app? Or is there more setup?
@marcotc I tried your suggestion of removing the registration of the sinatra middleware, and now I'm not seeing the sinatra.request
spans, just sinatra.route
ones:

Also, seeing this in the logs on startup, not sure if it's relevant or not:
WARN -- ddtrace: [ddtrace] Sinatra integration is misconfigured, reported traces will be missing request metadata such as path and HTTP status code. Did you forget to add
register Datadog::Tracing::Contrib::Sinatra::Tracer
to yourSinatra::Base
subclass? See https://docs.datadoghq.com/tracing/setup_overview/setup/ruby/#sinatra for more details.
important to note that we were seeing that on 0.54 and 1.0 before and after removing the middleware registration.
@delner
- They mostly look the same, but the top one has a
process-id
andruntime-id
whereas the other ones don't. The final one also has some extra tags we specifically added, that used to get attached to the sinatra.request span, but are now getting attached to the rack.request span. - I have no sinatra.request now after removing the registration, so I'll have to put that back in and get back to you.
- yes, we are using
require 'ddtrace/auto_instrument'
@delner by stack trace, you mean actual code stack trace? does that require profiling to be enabled? because I don't recall ever seeing stack traces for our system except for errors.
- The tags are correct (only top level spans should get process/runtime). Odd that tags ended up on Rack instead of Sinatra. (Maybe because span structure changed?)
- If you can print
caller
from inside that Sinatra request, it should give us an array of stack frames, which is the stack trace. That stack trace should show where and how it entered Rack instrumentation so many times. (Profiling is not required.) - Good to know. Not sure if this is a variable or not, just seems like instrumentation was applied multiple times, incorrectly.
My goal here is to be able to replicate this on our end... if we can do that, we can pull apart the instrumentation behavior and come up with a solid diagnosis and solution.
here's the stacktrace from inside a sinatra request:
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1685:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1685:in `block in compile!'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1071:in `block in process_route'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1069:in `catch'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1069:in `process_route'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1010:in `block in filter!'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1009:in `each'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1009:in `filter!'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1008:in `filter!'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1137:in `block in dispatch!'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1112:in `block in invoke'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1112:in `catch'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1112:in `invoke'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1135:in `dispatch!'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:949:in `block in call!'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1112:in `block in invoke'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1112:in `catch'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1112:in `invoke'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:949:in `call!'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:938:in `call'"
"/Users/michaelscrivo/affinity/patches/legacy_browser_detection.rb:17:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-2.2.3/lib/rack/null_logger.rb:11:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-2.2.3/lib/rack/head.rb:12:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/show_exceptions.rb:22:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:218:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/ddtrace-1.0.0/lib/datadog/tracing/contrib/rack/middlewares.rb:84:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1992:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1552:in `block in call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1768:in `synchronize'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1552:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-router-0.2.4/lib/sinatra/router.rb:81:in `block in try_route'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-router-0.2.4/lib/sinatra/router.rb:79:in `each'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-router-0.2.4/lib/sinatra/router.rb:79:in `try_route'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-router-0.2.4/lib/sinatra/router.rb:14:in `call'"
"/Users/michaelscrivo/affinity/patches/legacy_browser_detection.rb:17:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/secure_headers-6.3.3/lib/secure_headers/middleware.rb:11:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-protection-2.2.0/lib/rack/protection/base.rb:50:in `call'"
"/Users/mchaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-protection-2.2.0/lib/rack/protection/base.rb:50:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-router-0.2.4/lib/sinatra/router.rb:21:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-protection-2.2.0/lib/rack/protection/base.rb:50:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-router-0.2.4/lib/sinatra/router.rb:21:in `call'"
"/Users/michaelscrivo/affinity/lib/query_tracker.rb:273:in `block in call'"
"/Users/michaelscrivo/affinity/lib/query_tracker.rb:54:in `track_queries!'"
"/Users/michaelscrivo/affinity/lib/query_tracker.rb:273:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-parser-0.7.0/lib/rack/parser.rb:24:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-2.2.3/lib/rack/session/abstract/id.rb:266:in `context'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-2.2.3/lib/rack/session/abstract/id.rb:260:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-throttle-0.7.0/lib/rack/throttle/limiter.rb:35:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-throttle-0.7.0/lib/rack/throttle/limiter.rb:35:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-throttle-0.7.0/lib/rack/throttle/limiter.rb:35:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:996:in `forward'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1088:in `route_missing'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1037:in `route!'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1033:in `route!'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1140:in `block in dispatch!'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1112:in `block in invoke'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1112:in `catch'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1112:in `invoke'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1135:in `dispatch!'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:949:in `block in call!'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1112:in `block in invoke'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1112:in `catch'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1112:in `invoke'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:949:in `call!'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:938:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-2.2.3/lib/rack/null_logger.rb:11:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-2.2.3/lib/rack/head.rb:12:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/show_exceptions.rb:22:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:218:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/ddtrace-1.0.0/lib/datadog/tracing/contrib/rack/middlewares.rb:84:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1992:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-parser-0.7.0/lib/rack/parser.rb:24:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/request_store-1.5.1/lib/request_store/middleware.rb:19:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-protection-2.2.0/lib/rack/protection/xss_header.rb:18:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-protection-2.2.0/lib/rack/protection/path_traversal.rb:16:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-protection-2.2.0/lib/rack/protection/json_csrf.rb:26:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-protection-2.2.0/lib/rack/protection/base.rb:50:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-protection-2.2.0/lib/rack/protection/frame_options.rb:31:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-2.2.3/lib/rack/null_logger.rb:11:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-2.2.3/lib/rack/head.rb:12:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/show_exceptions.rb:22:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:218:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/ddtrace-1.0.0/lib/datadog/tracing/contrib/rack/middlewares.rb:84:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1992:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/puma-5.6.4/lib/puma/commonlogger.rb:40:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/puma-5.6.4/lib/puma/configuration.rb:252:in `call'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/puma-5.6.4/lib/puma/request.rb:77:in `block in handle_request'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/puma-5.6.4/lib/puma/thread_pool.rb:340:in `with_force_shutdown'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/puma-5.6.4/lib/puma/request.rb:76:in `handle_request'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/puma-5.6.4/lib/puma/server.rb:441:in `process_client'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/puma-5.6.4/lib/puma/thread_pool.rb:147:in `block in spawn_thread'"
"/Users/michaelscrivo/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/logging-2.3.0/lib/logging/diagnostic_context.rb:474:in `block in create_with_logging_context'"
These are the parts that are interesting:
"gems/sinatra-2.2.0/lib/sinatra/base.rb:218:in `call'"
"gems/ddtrace-1.0.0/lib/datadog/tracing/contrib/rack/middlewares.rb:84:in `call'"
"gems/sinatra-2.2.0/lib/sinatra/base.rb:1992:in `call'"
"gems/sinatra-2.2.0/lib/sinatra/base.rb:1552:in `block in call'"
...
"gems/sinatra-2.2.0/lib/sinatra/base.rb:218:in `call'"
"gems/ddtrace-1.0.0/lib/datadog/tracing/contrib/rack/middlewares.rb:84:in `call'"
"gems/sinatra-2.2.0/lib/sinatra/base.rb:1992:in `call'"
"gems/rack-parser-0.7.0/lib/rack/parser.rb:24:in `call'"
...
"gems/sinatra-2.2.0/lib/sinatra/base.rb:218:in `call'"
"gems/ddtrace-1.0.0/lib/datadog/tracing/contrib/rack/middlewares.rb:84:in `call'"
"gems/sinatra-2.2.0/lib/sinatra/base.rb:1992:in `call'"
"gems/puma-5.6.4/lib/puma/commonlogger.rb:40:in `call'"
Clearly the Rack trace middleware is being invoked at least 3 times, whereas it probably should only be invoked once (at the beginning of the Rack stack). We made some changes to our Sinatra instrumentation to support our new AppSec feature, so this is likely related.
I will attempt to recreate this on our end by setting up a new Sinatra app. Can you share your configuration, relevant structure of your Sinatra app? So I can create a replica to more thoroughly debug this? The more code/detail you can provide me, the more accurate the model, the more likely we can solve this. Thanks!
Sure .. so as you can see, we run the app with Puma, the puma config is pretty standard, it just calls rackup(app.ru)
and app.ru
looks like this:
# lots of stuff gets loaded here, including the datadog config (which I've shared above)
require_relative '../app'
use Datadog::Contrib::Rack::TraceMiddleware
run Apps::Web.new
Apps::Web
looks roughly like this:
module Apps
class Web < Base
configure do
set :protection
use Rack::Session::Cookie, COOKIE_OPTIONS.dup
use Rack::Parser
end
include Sinatra::ContentFor
use SecureHttpHeaders::Web
use Sinatra::Router do
# mount all controllers
end
end
end
That sinatra base class looks roughly like this:
module Apps
class Base < Sinatra::Base
use RequestStore::Middleware
configure do
set :root, File.expand_path('..', __dir__)
use Rack::Parser
end
register Sinatra::Hashfix
end
end
with this exercise, I'm noticing that we call use Rack::Parser
twice, so let me try removing one of those and see how things look.
Removing the extra Rack::Parser seems like it removed one of them maybe? Still doesn't seem to be anywhere near as clean as with 0.54

Also upgraded to the just released 1.1.0
The code you shared will be helpful. Thank you.
Trace shared doesn't look any different than the original?
Looking at the stack trace from before, it looked like the instrumentation was possibly injecting into Sinatra's Wrapper
, which is likely wrapping the Rack::Parser
. So something (Sinatra instrumentation) is probably injecting our trace middleware too many times. We should be able to make this trace much cleaner.
I wouldn't expect this to be fixed in 1.1.0 yet.
Any movement on this? We'd really like to upgrade from 0.54
@mscrivo I believe we did some work on this. Let me check in with @TonyCTHsu: he might know.
@mscrivo I believe we did some work on this. Let me check in with @TonyCTHsu: he might know.
Thanks. Still an issue as of 1.5.0
Hi @mscrivo , sorry its been a while.
From what I learned so far is that rack is generating nested spans from Sinatra. Although this is technically correct for Sinatra, the nested spans seem to be a noise and not so useful.
I have a PR I believe could improve the experience by squashing those nested spans (rack.request
and sinatra.request
). In addition, it simplifies instrumentation registration, no longer need to register tracer. Currently, I am collecting feedback from our Application Security team to see if the changes would break their implementation(sorry for the wait...).
Would you be willing to try out our pre-release gem to confirm whether such approach improves your experience and the flamegraph looks like something you would find useful?
source 'http://gems.datadoghq.com/prerelease-v2' do
gem 'ddtrace', '1.5.0.feature.sinatra.rack.279536'
end
This would help me understand if I am heading toward to right direction of solving this. Thanks
Thank you @TonyCTHsu .. I can definitely try that out. Will do as soon as I can and let you know how it looks.
@TonyCTHsu had a chance to try this out, it's looking great! pretty much like it did with 0.54, which makes me question whether I deployed my test branch properly ;)

Thanks so much for your work on this!
@mscrivo Thanks for the confirmation! I will try to make it in the next release.
👋 @mscrivo 1.6.0 has just released! Give it a try!
looking good so far @TonyCTHsu. Thanks again for all your work on this