Class: WideEvent::Middleware

Inherits:
Object
  • Object
show all
Defined in:
lib/wide_event/middleware.rb

Overview

Opens the wide-event accumulator for each request and flushes it to the configured sink as the response unwinds. With the OTel sink, the flush target is the root span opened by OTel's Rack instrumentation at the top of the stack. Must be inserted BELOW ActionDispatch::Executor: the executor clears IsolatedExecutionState on completion, so above it the store would be gone before the flush. The railtie handles placement.

Instance Method Summary collapse

Constructor Details

#initialize(app) ⇒ Middleware

Returns a new instance of Middleware.



15
16
17
# File 'lib/wide_event/middleware.rb', line 15

def initialize(app)
  @app = app
end

Instance Method Details

#call(env) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/wide_event/middleware.rb', line 19

def call(env)
  return @app.call(env) unless WideEvent.enabled?

  WideEvent.with do |attrs|
    seed(env)
    begin
      status, headers, body = @app.call(env)
      ex = env["action_dispatch.exception"]
      WideEvent.set(
        "http.response.status_code" => status.to_i,
        "error" => status.to_i >= 500 || attrs["error"] == true || !ex.nil?
      )
      if ex
        # Rendered by ActionDispatch::ShowExceptions before this
        # middleware's rescue ever fires: error attrs WITHOUT a slug,
        # same convention as the unhandled-exception path below.
        WideEvent.set("error" => true, "exception.type" => ex.class.name,
                      "exception.message" => ex.message.to_s[0, 500])
      end
      [ status, headers, body ]
    rescue Exception => e
      # Unhandled exception: error attrs WITHOUT a slug: the standing
      # "instrument this rescue" query keys off the missing slug.
      WideEvent.set("error" => true, "exception.type" => e.class.name,
                    "exception.message" => e.message.to_s[0, 500])
      raise
    ensure
      # Read at flush time, on every path (success AND unhandled
      # exception): ActionDispatch::RequestId runs deeper in the stack
      # and mutates env in place, so the id doesn't exist at seed time
      # but does by the time any outcome unwinds back to here.
      WideEvent.set("http.request.id" => env["action_dispatch.request_id"] || env["HTTP_X_REQUEST_ID"])
      WideEvent.flush(attrs)
    end
  end
end