Class: Foam::Otel::Rack::Middleware
- Inherits:
-
Object
- Object
- Foam::Otel::Rack::Middleware
- Defined in:
- lib/foam/otel/rack.rb
Overview
Inbound HTTP adapter — one span per request named "METHOD route", stamped inbound.http, per contract/SPEC.md sections 5, 6, and 10. Parent: traceparent header -> active context -> root. foam.rid baggage from x-request-id (or generated). request.context event with redacted query/headers/body/ip unless the route is exempted via health_routes. Anti-fabrication: exception event + ERROR only for unhandled raises;
=500 -> ERROR with no fabricated event; clean 4xx -> OK. Streaming (SSE) safe: the span ends when the response body closes, via Rack::BodyProxy — bodies are never buffered.
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#initialize(app, auto = false) ⇒ Middleware
constructor
autois set only when the railtie inserts this middleware; when true, an init(rails: false) opt-out (or init never having run) makes it a passthrough.
Constructor Details
#initialize(app, auto = false) ⇒ Middleware
auto is set only when the railtie inserts this middleware; when
true, an init(rails: false) opt-out (or init never having run)
makes it a passthrough. The check is per-request, so it doesn't
depend on init() having run before Rails built the middleware stack
(config/initializers run after that). A middleware added manually to
a bare-Rack app has auto=false and is always active.
31 32 33 34 |
# File 'lib/foam/otel/rack.rb', line 31 def initialize(app, auto = false) @app = app @auto = auto end |
Instance Method Details
#call(env) ⇒ Object
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 |
# File 'lib/foam/otel/rack.rb', line 36 def call(env) return @app.call(env) if @auto && !Foam::Otel.rails_enabled? Foam::Otel.check_fork! begin span, ctx, started_at, headers = start_span(env) rescue StandardError return @app.call(env) # never crash the request end token = OpenTelemetry::Context.attach(ctx) begin status, resp_headers, body = @app.call(env) wrapped = ::Rack::BodyProxy.new(body) do finish_span(span, env, status, started_at, headers) end [status, resp_headers, wrapped] rescue Exception => e # rubocop:disable Lint/RescueException record_unhandled(span, e) finish_span(span, env, 500, started_at, headers, error: true) raise ensure OpenTelemetry::Context.detach(token) end end |