class EpsagonRackMiddleware
Constants
- EMPTY_HASH
Public Class Methods
allowed_rack_request_headers()
click to toggle source
# File lib/instrumentation/epsagon_rails_middleware.rb, line 42 def allowed_rack_request_headers @allowed_rack_request_headers ||= Array(config[:allowed_request_headers]).each_with_object({}) do |header, memo| memo["HTTP_#{header.to_s.upcase.gsub(/[-\s]/, '_')}"] = build_attribute_name('http.request.headers.', header) end end
allowed_response_headers()
click to toggle source
# File lib/instrumentation/epsagon_rails_middleware.rb, line 48 def allowed_response_headers @allowed_response_headers ||= Array(config[:allowed_response_headers]).each_with_object({}) do |header, memo| memo[header] = build_attribute_name('http.response.headers.', header) memo[header.to_s.upcase] = build_attribute_name('http.response.headers.', header) end end
build_attribute_name(prefix, suffix)
click to toggle source
# File lib/instrumentation/epsagon_rails_middleware.rb, line 55 def build_attribute_name(prefix, suffix) prefix + suffix.to_s.downcase.gsub(/[-\s]/, '_') end
config()
click to toggle source
# File lib/instrumentation/epsagon_rails_middleware.rb, line 59 def config EpsagonRailsInstrumentation.instance.config end
new(app)
click to toggle source
# File lib/instrumentation/epsagon_rails_middleware.rb, line 73 def initialize(app) @app = app end
Private Class Methods
clear_cached_config()
click to toggle source
# File lib/instrumentation/epsagon_rails_middleware.rb, line 65 def clear_cached_config @allowed_rack_request_headers = nil @allowed_response_headers = nil end
Public Instance Methods
call(env)
click to toggle source
# File lib/instrumentation/epsagon_rails_middleware.rb, line 77 def call(env) original_env = env.dup # restore extracted context in this process: OpenTelemetry::Context.with_current(OpenTelemetry.propagation.http.extract(env)) do request_span_name = create_request_span_name(env['REQUEST_URI'] || original_env['PATH_INFO']) tracer.in_span(env['HTTP_HOST'] || 'unknown', attributes: request_span_attributes(env: env), kind: :server) do |http_span| RackExtension.with_span(http_span) do tracer.in_span( env['HTTP_HOST'], kind: :server, attributes: {type: 'rails'} ) do |framework_span| @app.call(env).tap do |status, headers, response| set_attributes_after_request(http_span, framework_span, status, headers, response) end end end end end end
Private Instance Methods
allowed_request_headers(env)
click to toggle source
# File lib/instrumentation/epsagon_rails_middleware.rb, line 180 def allowed_request_headers(env) return EMPTY_HASH if self.class.allowed_rack_request_headers.empty? {}.tap do |result| self.class.allowed_rack_request_headers.each do |key, value| result[value] = env[key] if env.key?(key) end end end
allowed_response_headers(headers)
click to toggle source
# File lib/instrumentation/epsagon_rails_middleware.rb, line 190 def allowed_response_headers(headers) return EMPTY_HASH if headers.nil? return EMPTY_HASH if self.class.allowed_response_headers.empty? {}.tap do |result| self.class.allowed_response_headers.each do |key, value| if headers.key?(key) result[value] = headers[key] else # do case-insensitive match: headers.each do |k, v| if k.upcase == key result[value] = v break end end end end end end
config()
click to toggle source
# File lib/instrumentation/epsagon_rails_middleware.rb, line 211 def config EpsagonRailsInstrumentation.instance.config end
create_request_span_name(request_uri_or_path_info)
click to toggle source
github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-http.md#name
recommendation: span.name(s) should be low-cardinality (e.g., strip off query param value, keep param name)
see github.com/open-telemetry/opentelemetry-specification/pull/416/files
# File lib/instrumentation/epsagon_rails_middleware.rb, line 159 def create_request_span_name(request_uri_or_path_info) # NOTE: dd-trace-rb has implemented 'quantization' (which lowers url cardinality) # see Datadog::Quantization::HTTP.url if (implementation = config[:url_quantization]) implementation.call(request_uri_or_path_info) else request_uri_or_path_info end end
finish_span(context)
click to toggle source
# File lib/instrumentation/epsagon_rails_middleware.rb, line 103 def finish_span(context) OpenTelemetry::Trace.current_span(context).finish if context end
fullpath(env)
click to toggle source
e.g., “/webshop/articles/4?s=1”:
# File lib/instrumentation/epsagon_rails_middleware.rb, line 146 def fullpath(env) query_string = env['QUERY_STRING'] path = env['SCRIPT_NAME'] + env['PATH_INFO'] query_string.empty? ? path : "#{path}?#{query_string}" end
request_span_attributes(env:)
click to toggle source
# File lib/instrumentation/epsagon_rails_middleware.rb, line 111 def request_span_attributes(env:) request = Rack::Request.new(env) path, path_params = request.path.split(';') request_headers = JSON.generate(Hash[*env.select { |k, _v| k.to_s.start_with? 'HTTP_' } .collect { |k, v| [k.sub(/^HTTP_/, ''), v] } .collect { |k, v| [k.split('_').collect(&:capitalize).join('-'), v] } .sort .flatten]) attributes = { 'operation' => env['REQUEST_METHOD'], 'type' => 'http', 'http.scheme' => env['rack.url_scheme'], 'http.request.path' => path, 'http.request.headers' => request_headers } unless config[:epsagon][:metadata_only] request.body.rewind request_body = request.body.read request.body.rewind attributes.merge!(Util.epsagon_query_attributes(request.query_string)) attributes.merge!({ 'http.request.body' => request_body, 'http.request.path_params' => path_params, 'http.request.headers.User-Agent' => env['HTTP_USER_AGENT'] }) end attributes end
set_attributes_after_request(http_span, _framework_span, status, headers, response)
click to toggle source
# File lib/instrumentation/epsagon_rails_middleware.rb, line 170 def set_attributes_after_request(http_span, _framework_span, status, headers, response) unless config[:epsagon][:metadata_only] http_span.set_attribute('http.response.headers', JSON.generate(headers)) http_span.set_attribute('http.response.body', response.join) if response.respond_to?(:join) end http_span.set_attribute('http.status_code', status) http_span.status = OpenTelemetry::Trace::Status.http_to_status(status) end
tracer()
click to toggle source
# File lib/instrumentation/epsagon_rails_middleware.rb, line 107 def tracer EpsagonRailsInstrumentation.instance.tracer end