Class: Foam::Otel::Rack::Middleware

Inherits:
Object
  • Object
show all
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

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