Class: AllStak::Integrations::Rack::Middleware
- Inherits:
-
Object
- Object
- AllStak::Integrations::Rack::Middleware
- Defined in:
- lib/allstak/integrations/rack.rb
Overview
Rack middleware that:
-
Starts a fresh trace per request (or adopts X-AllStak-Trace-Id / traceparent)
-
Captures inbound HTTP request telemetry
-
Auto-captures unhandled exceptions with full request context, user, stack, and trace link
-
Re-raises so the framework’s exception handler runs
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#initialize(app) ⇒ Middleware
constructor
A new instance of Middleware.
Constructor Details
#initialize(app) ⇒ Middleware
Returns a new instance of Middleware.
10 11 12 |
# File 'lib/allstak/integrations/rack.rb', line 10 def initialize(app) @app = app end |
Instance Method Details
#call(env) ⇒ Object
14 15 16 17 18 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 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 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/allstak/integrations/rack.rb', line 14 def call(env) return @app.call(env) unless AllStak.initialized? client = AllStak.client config = client.config start = now_ms started_at = Time.now.utc.iso8601(3) # Trace id — adopt incoming or mint fresh per request incoming = env["HTTP_X_ALLSTAK_TRACE_ID"] || env["HTTP_TRACEPARENT"] if incoming && !incoming.empty? client.tracing.set_trace_id(incoming) else client.tracing.reset_trace end trace_id = client.tracing.current_trace_id status = 0 headers = {} body = nil captured = nil begin status, headers, body = @app.call(env) rescue => e captured = e status = 500 if status.to_i == 0 raise ensure duration = now_ms - start # Request telemetry if config.capture_http_requests begin req_size = env["CONTENT_LENGTH"].to_i resp_size = headers && headers["Content-Length"].to_i user_id = extract_user_id(env) path = env["PATH_INFO"] || "/" client.http.record( direction: "inbound", method: env["REQUEST_METHOD"] || "GET", host: env["HTTP_HOST"] || "localhost", path: path, status_code: status.to_i, duration_ms: duration, request_size: req_size, response_size: resp_size || 0, trace_id: trace_id, user_id: user_id ) rescue => err # never raise into host config.debug && warn("[AllStak] rack request capture failed: #{err.}") end end # Exception capture if captured && config.capture_unhandled_exceptions begin user_ctx = config.capture_user_context ? build_user_context(env) : nil req_ctx = AllStak::Models::RequestContext.new( method: env["REQUEST_METHOD"], path: env["PATH_INFO"], host: env["HTTP_HOST"], status_code: status.to_i == 0 ? 500 : status.to_i, user_agent: env["HTTP_USER_AGENT"] ) = { "http.method" => env["REQUEST_METHOD"], "http.path" => env["PATH_INFO"], "http.host" => env["HTTP_HOST"], "http.status" => status.to_i == 0 ? 500 : status.to_i, "traceId" => trace_id } client.errors.capture_exception( captured, user: user_ctx, request_context: req_ctx, trace_id: trace_id, metadata: ) rescue => err config.debug && warn("[AllStak] rack exception capture failed: #{err.}") end end # Best-effort response header for downstream trace linkage headers["X-AllStak-Trace-Id"] = trace_id if headers && !captured end [status, headers, body] end |