-
Notifications
You must be signed in to change notification settings - Fork 178
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
feat: Use Rack::Events for instrumentation #342
feat: Use Rack::Events for instrumentation #342
Conversation
# @note does nothing if the span is a non-recording span | ||
# @param [Rack::Request] The current HTTP request | ||
# @param [Rack::Response] The current HTTP response | ||
def on_finish(request, response) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might also be nice to add on_send
and record a span event for "sent first byte" or something similar. It is really nice to know, from a perf analysis perspective, when the application has finalized the response and the remaining work is "out of our hands".
An interesting philosophical question: when should we consider the server span "finished"? When application processing is complete or when the response has been completely written to the socket? I think the current middleware implementation is effectively equivalent to "when application processing is complete", before anything has been written to the socket.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might also be nice to add
on_send
and record a span event for "sent first byte" or something similar. It is really nice to know, from a perf analysis perspective, when the application has finalized the response and the remaining work is "out of our hands".
I like this idea a lot! I will add it to my todo list.
An interesting philosophical question: when should we consider the server span "finished"? When application processing is complete or when the response has been completely written to the socket? I think the current middleware implementation is effectively equivalent to "when application processing is complete", before anything has been written to the socket.
- 💭 I'm not sure. I lean towards after the middleware has completed writing the response but does that make it asymmetric from when it's processing the incoming request? I'm not entirely certain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Going to hold off adding other events until I get this initial implementation merged.
I am also going to stick with on_finish
, i.e. after the response has been written to the socket and the Rack::BufferedResponse
is closed.
instrumentation/rack/lib/opentelemetry/instrumentation/rack/middlewares/event_handler.rb
Outdated
Show resolved
Hide resolved
instrumentation/rack/lib/opentelemetry/instrumentation/rack/middlewares/event_handler.rb
Show resolved
Hide resolved
instrumentation/rack/lib/opentelemetry/instrumentation/rack/middlewares/event_handler.rb
Outdated
Show resolved
Hide resolved
instrumentation/rack/lib/opentelemetry/instrumentation/rack/middlewares/event_handler.rb
Outdated
Show resolved
Hide resolved
This is an alternate implementation of the Rack instrumentation that leverages the [`Rack::Events` API](https://www.rubydoc.info/gems/rack/Rack/Events) instead of a custom`Rack::Middleware`. Why am I suggesting we change this instrumentation? At GitHub we leverage `Rack::BodyProxy` to write Rack Request logs after the request is complete, however Rack span is already finished and its related `Context` has already been detached. This means we are not able to correlate request logs to our traces. The advantage of using `Rack::Events` is that handlers are triggered during difference stages of a request, including for deferred operations like [`Rack::BodyProxy`](https://www.rubydoc.info/gems/rack/Rack/BodyProxy), as opposed to middlewares who _only_ are invoked inline. The disadvantage of this API is that it makes managing the request more difficult and we have to track the Context positions to detach in the `Rack::Env`. This implementation will be released along side the existing instrumtation to give users the option to use the middleware instead of the `Rack::Events` handler until we are able to run this in some of our heavy production workloads. Fixes open-telemetry#341 Related DataDog/dd-trace-rb#1746
2272df2
to
5261676
Compare
…ash when it encounters errors
Tests are failing for combination of rack >= 2.2 and rack test 2.1 |
I have opened an issue with Hopefully I will be able to dig in something soon and see what is going on. |
|
# This option is only valid for applicaitons using Rack 2.0 or greater | ||
option :use_rack_events, default: false, validate: :boolean | ||
|
||
# Temporary Helper for Sinatra and ActionPack middleware to use during installation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the long term plan (you may have answered this elsewhere)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This configuration setting and helper will exist until...
- We drop support for Sinatra versions that require Rack 1.x
- A future release that makes the Event Handler the default way for users to instrument their applications
require_relative 'middlewares/tracer_middleware' | ||
end | ||
|
||
def config_options(user_config) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@robertlaurin is config_options
intended to be overridden? It looks OK to me, but I don't think we've explicitly called it out as OK for instrumentation to override.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fbogsany @robertlaurin Is this a blocker for merging and releasing the event-based implementation?
@@ -6,8 +6,6 @@ | |||
|
|||
require 'opentelemetry/trace/status' | |||
|
|||
require_relative '../util/queue_time' | |||
|
|||
module OpenTelemetry | |||
module Instrumentation | |||
module Rack |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason not to update this to use the config[:allowed_rack_request_headers]
and config[:allowed_rack_response_headers]
precomputed in the Instrumentation
class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was worried about changing too many things at once in this PR.
I am certainly amenable to removing the duplication here.
def record_frontend_span? | ||
config[:record_frontend_span] == true | ||
end | ||
|
||
def untraced_endpoints | ||
config[:untraced_endpoints] | ||
end | ||
|
||
def untraced_requests | ||
config[:untraced_requests] | ||
end | ||
|
||
def url_quantization | ||
config[:url_quantization] | ||
end | ||
|
||
def response_propagators | ||
config[:response_propagators] | ||
end | ||
|
||
def allowed_request_headers | ||
config[:allowed_rack_request_headers] | ||
end | ||
|
||
def allowed_response_headers | ||
config[:allowed_rack_response_headers] | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason not to cache all these config options in instance variables?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The existing instrumentation supports being able to inject the middleware and then initializing the SDK afterwards.
Using instance variables made it so the instance in the middleware had stale values and did not reflect the values after the instrumentation was installed so I didn't have a choice but to look them up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that caching config option values in instance variables is not a blocker to adding the event-based implementation. 👍🏻
I think caching (I'm assuming "via memoization" here) is something we could consider doing in a future release if/when the middleware-based implementation is removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It hangs together, new behavior is behind a feature flag config option, old behavior works in the handful of Racky test apps I have.
# in a Gemfile
gem 'opentelemetry-instrumentation-rack', git: 'https://github.com/open-telemetry/opentelemetry-ruby-contrib', glob: 'instrumentation/*/*.gemspec'
I'd like to see the instrumentation's options appear documented in the gem's README, but (1) of the existing options, only url_quantization
is mentioned so this is not really a hard criteria for this new option and (2) I can be the change I want to see in the world (I'll open a PR updating the README).
OOOOOOOOPPPPPPPPPPPPSSSSSS I had set this to auto-merge by accident. I hope that is not a problem. |
This is an alternate implementation of the Rack instrumentation that leverages the
Rack::Events
API instead of a customRack::Middleware
.Why am I suggesting we change this instrumentation? At GitHub we leverage
Rack::BodyProxy
to write Rack Request logs after the request is complete, however Rack span is already finished and its relatedContext
has already been detached. This means we are not able to correlate request logs to our traces.The advantage of using
Rack::Events
is that handlers are triggered during difference stages of a request, including for deferred operations likeRack::BodyProxy
, as opposed to middlewares who only are invoked inline.The disadvantage of this API is that it makes managing the request more difficult and we have to track the Context positions to detach in the
Rack::Env
.This implementation will be released along side the existing instrumtation to give users the option to use the middleware instead of the
Rack::Events
handler until we are able to run this in some of our heavy production workloads.Other noteworthy things:
http.proxy
span has been converted to a Span Event and ignores therecord_frontend_span
optionRack::Instrumentation.install
Fixes #341 Related DataDog/dd-trace-rb#1746