Class: LaunchDarklyObservability::Middleware

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

Overview

Rack middleware for request tracing

This middleware wraps incoming HTTP requests in OpenTelemetry spans, providing context for flag evaluations that occur during request processing.

Works with any Rack-compatible framework (Rails, Sinatra, Grape, Hanami, etc.). In Rails, the Railtie inserts this middleware automatically. For other frameworks, add it manually to your middleware stack:

Examples:

Sinatra

use LaunchDarklyObservability::Middleware

Rack::Builder

use LaunchDarklyObservability::Middleware
run MyApp

Constant Summary collapse

OBSERVABILITY_REQUEST_HEADER =

Header for observability request context (session/request ID propagation)

'HTTP_X_HIGHLIGHT_REQUEST'
SESSION_BAGGAGE_KEY =

Baggage keys for context propagation

'launchdarkly.session_id'
REQUEST_BAGGAGE_KEY =
'launchdarkly.request_id'

Instance Method Summary collapse

Constructor Details

#initialize(app) ⇒ Middleware

Returns a new instance of Middleware.



28
29
30
# File 'lib/launchdarkly_observability/middleware.rb', line 28

def initialize(app)
  @app = app
end

Instance Method Details

#call(env) ⇒ Array

Process the request with tracing context

Parameters:

  • env (Hash)

    Rack environment

Returns:

  • (Array)

    Rack response tuple



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
# File 'lib/launchdarkly_observability/middleware.rb', line 36

def call(env)
  return @app.call(env) unless tracing_available?

  request = Rack::Request.new(env)
  session_id, request_id = extract_observability_context(env)
  ctx = set_baggage_context(session_id, request_id)
  app_error = nil

  OpenTelemetry::Context.with_current(ctx) do
    tracer.in_span(span_name(request), attributes: request_attributes(request)) do |span|
      span.set_attribute(SESSION_BAGGAGE_KEY, session_id) if session_id
      span.set_attribute(REQUEST_BAGGAGE_KEY, request_id) if request_id

      begin
        status, headers, body = @app.call(env)
      rescue StandardError => e
        app_error = e
        span.record_exception(e, attributes: SourceContext.exception_attributes(e))
        span.status = OpenTelemetry::Trace::Status.error(e.message)
        raise
      end

      span.set_attribute('http.status_code', status)
      span.status = OpenTelemetry::Trace::Status.error("HTTP #{status}") if status >= 500
      [status, headers, body]
    end
  end
rescue StandardError => e
  raise if app_error

  warn "[LaunchDarklyObservability] Middleware error: #{e.message}"
  @app.call(env)
end