class Skylight::Core::Middleware

@api private

Attributes

config[R]

Public Class Methods

log_target() click to toggle source
# File lib/skylight/core/middleware.rb, line 68
def self.log_target
  @log_target ||= (Skylight::Core::Fanout.registered.first&.config || Logger.new(STDERR))
end
new(app, opts = {}) click to toggle source
# File lib/skylight/core/middleware.rb, line 77
def initialize(app, opts = {})
  @app = app
  @config = opts[:config]
end
with_after_close(resp, debug_identifier: "unknown", &block) click to toggle source
# File lib/skylight/core/middleware.rb, line 47
def self.with_after_close(resp, debug_identifier: "unknown", &block)
  # Responses should be arrays but in some situations they aren't
  #   e.g. https://github.com/ruby-grape/grape/issues/1041
  # See also https://github.com/rack/rack/issues/1239

  unless resp.respond_to?(:to_ary)
    if resp.respond_to?(:to_a)
      log_target.warn("Rack response from \"#{debug_identifier}\" cannot be implicitly converted to an array. This is in violation of "\
                      "the Rack SPEC and will raise an error in future versions.")
      resp = resp.to_a
    else
      log_target.error("Rack response from \"#{debug_identifier}\" cannot be converted to an array. This is in violation of the Rack SPEC "\
                      "and may cause problems with Skylight operation.")
      return resp
    end
  end

  status, headers, body = resp
  [status, headers, BodyProxy.new(body, &block)]
end

Public Instance Methods

call(env) click to toggle source
# File lib/skylight/core/middleware.rb, line 82
def call(env)
  set_request_id(env)

  if instrumentable.tracing?
    error "Already instrumenting. Make sure the Skylight Rack Middleware hasn't been added more than once."
  end

  if env["REQUEST_METHOD"] == "HEAD"
    t { "middleware skipping HEAD" }
    @app.call(env)
  else
    begin
      t { "middleware beginning trace" }
      trace = instrumentable.trace(endpoint_name(env), "app.rack.request", nil, meta: endpoint_meta(env), component: :web)
      t { "middleware began trace=#{trace ? trace.uuid : nil}" }

      resp = @app.call(env)

      if trace
        Middleware.with_after_close(resp, debug_identifier: "Rack App: #{@app.class}") { trace.submit }
      else
        resp
      end
    rescue Exception => e
      t { "middleware exception: #{e}\n#{e.backtrace.join("\n")}" }
      trace.submit if trace
      raise
    end
  end
end

Private Instance Methods

endpoint_meta(_env) click to toggle source
# File lib/skylight/core/middleware.rb, line 130
def endpoint_meta(_env)
  nil
end
endpoint_name(_env) click to toggle source

Allow for overwriting

# File lib/skylight/core/middleware.rb, line 126
def endpoint_name(_env)
  "Rack"
end
instrumentable() click to toggle source
# File lib/skylight/core/middleware.rb, line 121
def instrumentable
  Skylight
end
internal_request_id() click to toggle source
# File lib/skylight/core/middleware.rb, line 148
def internal_request_id
  SecureRandom.uuid
end
log_context() click to toggle source
# File lib/skylight/core/middleware.rb, line 115
def log_context
  # Don't cache this, it will change
  inst_id = instrumentable.instrumenter ? instrumentable.instrumenter.uuid : nil
  { request_id: @current_request_id, inst: inst_id }
end
make_request_id(request_id) click to toggle source
# File lib/skylight/core/middleware.rb, line 140
def make_request_id(request_id)
  if request_id && !request_id.empty?
    request_id.gsub(/[^\w\-]/, "".freeze)[0...255]
  else
    internal_request_id
  end
end
set_request_id(env) click to toggle source

Request ID code based on ActionDispatch::RequestId

# File lib/skylight/core/middleware.rb, line 135
def set_request_id(env)
  existing_request_id = env["action_dispatch.request_id"] || env["HTTP_X_REQUEST_ID"]
  @current_request_id = env["skylight.request_id"] = make_request_id(existing_request_id)
end