class OneApm::Rack::BrowserMonitoring
Constants
- OA_ALREADY_INSTRUMENTED_KEY
- OA_CHARSET_RE
- OA_REMOTE_IP
- OA_SCAN_LIMIT
- OA_X_UA_COMPATIBLE_RE
Public Instance Methods
autoinstrument_source(response, headers, js_to_inject)
click to toggle source
# File lib/one_apm/rack/browser_monitoring.rb, line 84 def autoinstrument_source(response, headers, js_to_inject) begin source = gather_source(response) close_old_response(response) return nil unless source inject_js(source, headers, js_to_inject) rescue => e OneApm::Manager.logger.debug "Skipping RUM instrumentation on exception.", e nil end end
calculate_content_length(source)
click to toggle source
String does not respond to 'bytesize' in 1.8.6. Fortunately String#length returns bytes rather than characters in 1.8.6 so we can use that instead.
# File lib/one_apm/rack/browser_monitoring.rb, line 172 def calculate_content_length(source) if source.respond_to?(:bytesize) source.bytesize else source.length end end
find_body_end(source)
click to toggle source
# File lib/one_apm/rack/browser_monitoring.rb, line 150 def find_body_end source source.rindex("</body>") end
find_body_start(beginning_of_source)
click to toggle source
# File lib/one_apm/rack/browser_monitoring.rb, line 146 def find_body_start(beginning_of_source) beginning_of_source.index("<body") end
find_charset_position(beginning_of_source)
click to toggle source
# File lib/one_apm/rack/browser_monitoring.rb, line 160 def find_charset_position(beginning_of_source) match = OA_CHARSET_RE.match(beginning_of_source) match.end(0) if match end
find_end_of_head_open(beginning_of_source)
click to toggle source
# File lib/one_apm/rack/browser_monitoring.rb, line 165 def find_end_of_head_open(beginning_of_source) head_open = beginning_of_source.index("<head") beginning_of_source.index(">", head_open) + 1 if head_open end
find_x_ua_compatible_position(beginning_of_source)
click to toggle source
# File lib/one_apm/rack/browser_monitoring.rb, line 155 def find_x_ua_compatible_position(beginning_of_source) match = OA_X_UA_COMPATIBLE_RE.match(beginning_of_source) match.end(0) if match end
header_index(source)
click to toggle source
# File lib/one_apm/rack/browser_monitoring.rb, line 113 def header_index source beginning_of_source = source[0..OA_SCAN_LIMIT] if body_start = find_body_start(beginning_of_source) meta_tag_positions = [ find_x_ua_compatible_position(beginning_of_source), find_charset_position(beginning_of_source) ].compact if !meta_tag_positions.empty? insertion_index = meta_tag_positions.max else insertion_index = find_end_of_head_open(beginning_of_source) || body_start end insertion_index else msg = "Skipping RUM instrumentation. Unable to find <body> tag in first #{OA_SCAN_LIMIT} bytes of document." OneApm::Manager.logger.log_once(:warn, :rum_insertion_failure, msg) OneApm::Manager.logger.debug(msg) nil end end
inject_js(source, headers, js_to_inject)
click to toggle source
# File lib/one_apm/rack/browser_monitoring.rb, line 96 def inject_js source, headers, js_to_inject position = OneApm::Manager.config[:'browser_monitoring.position'] insertion_index = (position.empty? || position.to_sym != :footer) ? header_index(source) : footer_index(source) if insertion_index source = source[0...insertion_index] \ << js_to_inject \ << source[insertion_index..-1] if headers['Content-Length'] headers['Content-Length'] = calculate_content_length(source).to_s end else OneApm::Manager.logger.debug "Skipping RUM instrumentation. Could not properly determine location to inject script." end source end
ip_valid?(env)
click to toggle source
# File lib/one_apm/rack/browser_monitoring.rb, line 62 def ip_valid?(env) whitelist_ips = OneApm::Manager.config[:'browser_monitoring.whitelist_ips'] return true if whitelist_ips.empty? || env[OA_REMOTE_IP].to_s.empty? OneApm::Manager.logger.debug "Remote IP: #{env[OA_REMOTE_IP]}" begin client = IPAddr.new(env[OA_REMOTE_IP].to_s).to_i whitelist_ips.split(",").any? do |ip| low_ip, high_ip = ip.split("-").map(&:strip) low = IPAddr.new(low_ip).to_i if high_ip high = IPAddr.new(high_ip).to_i (low..high) === client else low == client end end rescue => e OneApm::Manager.logger.error "Configuration for browser_monitoring.whitelist_ips has problems:#{whitelist_ips}" true end end
is_attachment?(headers)
click to toggle source
# File lib/one_apm/rack/browser_monitoring.rb, line 53 def is_attachment?(headers) headers['Content-Disposition'].to_s.include?('attachment') end
is_html?(headers)
click to toggle source
# File lib/one_apm/rack/browser_monitoring.rb, line 49 def is_html?(headers) headers["Content-Type"] && headers["Content-Type"].include?("text/html") end
is_streaming?(env)
click to toggle source
# File lib/one_apm/rack/browser_monitoring.rb, line 57 def is_streaming?(env) return false unless defined?(ActionController::Live) env['action_controller.instance'].class.included_modules.include?(ActionController::Live) end
should_instrument?(env, status, headers)
click to toggle source
# File lib/one_apm/rack/browser_monitoring.rb, line 39 def should_instrument?(env, status, headers) OneApm::Manager.config[:'browser_monitoring.auto_instrument'] && status == 200 && !env[OA_ALREADY_INSTRUMENTED_KEY] && is_html?(headers) && !is_attachment?(headers) && !is_streaming?(env) && ip_valid?(env) end
traced_call(env)
click to toggle source
# File lib/one_apm/rack/browser_monitoring.rb, line 20 def traced_call(env) result = @app.call(env) # [status, headers, response] js_to_inject = OneApm::Manager.browser_timing_header if (js_to_inject != "") && should_instrument?(env, result[0], result[1]) response_string = autoinstrument_source(result[2], result[1], js_to_inject) env[OA_ALREADY_INSTRUMENTED_KEY] = true if response_string response = ::Rack::Response.new(response_string, result[0], result[1]) response.finish else result end else result end end