Class: Datadog::Contrib::Rack::RumInjection
- Inherits:
-
Object
- Object
- Datadog::Contrib::Rack::RumInjection
- Includes:
- Environment::Helpers
- Defined in:
- lib/ddtrace/contrib/rack/rum_injection.rb
Overview
RumInjection ensures that the Rack Response has rum information injected into it's html. The middleware modifies the response body of non-cached html so that it can be retrieved by the rum browser-sdk in the application frontend.
Constant Summary collapse
- RUM_INJECTION_FLAG =
'datadog.rum_injection_flag'.freeze
- INLINE =
'inline'.freeze
- IDENTITY =
'identity'.freeze
- HTML_CONTENT =
'text/html'.freeze
- XHTML_CONTENT =
'application/xhtml+xml'.freeze
- NO_CACHE =
'no-cache'.freeze
- NO_STORE =
'no-store'.freeze
- PRIVATE =
'private'.freeze
- MAX_AGE =
'max-age'.freeze
- SMAX_AGE =
's-maxage'.freeze
- MAX_AGE_ZERO =
'max-age=0'.freeze
- SMAX_AGE_ZERO =
's-maxage=0'.freeze
- CONTENT_TYPE_STREAMING =
'text/event-stream'.freeze
- CACHE_CONTROL_HEADER =
'Cache-Control'.freeze
- CONTENT_DISPOSITION_HEADER =
'Content-Disposition'.freeze
- CONTENT_ENCODING_HEADER =
'Content-Encoding'.freeze
- CONTENT_LENGTH_HEADER =
'Content-Length'.freeze
- CONTENT_TYPE_HEADER =
'Content-Type'.freeze
- EXPIRES_HEADER =
'Expires'.freeze
- SURROGATE_CACHE_CONTROL_HEADER =
'Surrogate-Control'.freeze
- TRANSFER_ENCODING_HEADER =
'Transfer-Encoding'.freeze
- ACTION_CONTROLLER_INSTANCE =
'action_controller.instance'.freeze
- TRANSFER_ENCODING_CHUNKED =
'chunked'.freeze
Class Method Summary collapse
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#initialize(app) ⇒ RumInjection
constructor
A new instance of RumInjection.
Methods included from Environment::Helpers
#env_to_bool, #env_to_float, #env_to_int, #env_to_list
Constructor Details
#initialize(app) ⇒ RumInjection
Returns a new instance of RumInjection.
41 42 43 |
# File 'lib/ddtrace/contrib/rack/rum_injection.rb', line 41 def initialize(app) @app = app end |
Class Method Details
.inject_rum_data(supplied_env = nil) ⇒ Object
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/ddtrace/contrib/rack/rum_injection.rb', line 94 def self.inject_rum_data(supplied_env = nil) tracer = Datadog.configuration[:rack][:tracer] return '' unless tracer.enabled span = tracer.active_span # only return trace id if sampled trace_id = span && span.sampled ? span.trace_id : nil return '' unless trace_id begin # the user can ensure there is not a double patching from auto-injection # by passing in the rack env so that a flag can be set. This flag is checked # later by auto injection. the goal is to support main frameworks and # document what we support OOTB. Most frameworks that are rack compatible also expose # a helper in the framework controller/template the user can use to access the rack env # request.env (rails), env (rails/sinatra/grape?). Should provide example snippets. supplied_env[RUM_INJECTION_FLAG] = true if supplied_env rescue StandardError => error Datadog.logger.debug("rack request Environment unavailable: #{error.}") end unix_time = DateTime.now.strftime('%Q').to_i tag_string = %(\n<meta name="dd-trace-id" content="#{trace_id}" />\ <meta name="dd-trace-time" content="#{unix_time}" />) tag_string.respond_to?(:html_safe) ? tag_string.html_safe : tag_string rescue StandardError => err # maybe shouldnt log in case datadog is disabled or not required in? Datadog.logger.warn("datadog inject_rum_data failed: #{err.}") '' end |
Instance Method Details
#call(env) ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/ddtrace/contrib/rack/rum_injection.rb', line 45 def call(env) result = @app.call(env) begin return result unless configuration[:rum_injection_enabled] == true status, headers, body = result # need significant safety here to ensure result is parsable + injectable # shouldn't be gzipped/compressed yet since we've injected our middleware in the stack after rack deflater # or any other compression middleware for that matter # also ensure its non-cacheable, is html, is not streaming, and is not an attachment return result unless headers && should_inject?(headers, env) trace_id = current_trace_id # do not inject if no trace or trace is not sampled return result unless trace_id # update content length and return new response if we don't fail on rum injection if body.respond_to?(:each) # we need to insert the trace_id and expiry meta tags unix_time = DateTime.now.strftime('%Q').to_i html_comment = html_comment_template(trace_id, unix_time) rum_body = RumBody.new(body, html_comment) update_content_length(headers, html_comment) # ensure idempotency on injection in case middleware is inserted or called twice env[RUM_INJECTION_FLAG] = true updated_response = ::Rack::Response.new(rum_body, status, headers) Datadog.logger.debug { "Rum injection successful: #{html_comment}" } return updated_response.finish else Datadog.logger.debug('Rum injection unsuccessful') return result end # catchall if an earlier conditional is not met result rescue StandardError => e Datadog.logger.warn("error checking rum injectability #{e.class}: #{e.} #{e.backtrace.join("\n")}") # we should ensure we don't interfere if original app response if our injection code has an exception result end end |