Class: OpenTelemetry::Instrumentation::Rack::Middlewares::EventHandler

Inherits:
Object
  • Object
show all
Includes:
Rack::Events::Abstract
Defined in:
lib/opentelemetry/instrumentation/rack/middlewares/event_handler.rb

Overview

OTel Rack Event Handler

This seeds the root context for this service with the server span as the current_span allowing for callers later in the stack to reference it using Trace.current_span

It also registers the server span in a context dedicated to this instrumentation that users may look up using OpenTelemetry::Instrumentation::Rack.current_span, which makes it possible for users to mutate the span, e.g. add events or update the span name like in the ActionPack instrumentation.

Examples:

Rack App Using BodyProxy

GLOBAL_LOGGER = Logger.new($stderr)
APP_TRACER = OpenTelemetry.tracer_provider.tracer('my-app', '1.0.0')

Rack::Builder.new do
  use Rack::Events, [OpenTelemetry::Instrumentation::Rack::Middlewares::EventHandler.new]
  run lambda { |_arg|
    APP_TRACER.in_span('hello-world') do |_span|
      body = Rack::BodyProxy.new(['hello world!']) do
        rack_span = OpenTelemetry::Instrumentation::Rack.current_span
        GLOBAL_LOGGER.info("otel.trace_id=#{rack_span.context.hex_trace_id} otel.span_id=#{rack_span.context.hex_span_id}")
      end
      [200, { 'Content-Type' => 'text/plain' }, body]
    end
  }
end

See Also:

  • Rack::Events
  • OpenTelemetry::Instrumentation::Rack.current_span

Constant Summary collapse

OTEL_TOKEN_AND_SPAN =
'otel.rack.token_and_span'
GOOD_HTTP_STATUSES =
(100..499)

Instance Method Summary collapse

Instance Method Details

#on_commit(request, response) ⇒ void

This method returns an undefined value.

Optionally adds debugging response headers injected from #response_propagators

Parameters:

  • The (Rack::Request)

    current HTTP request

  • This (Rack::Response)

    current HTTP response



74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/opentelemetry/instrumentation/rack/middlewares/event_handler.rb', line 74

def on_commit(request, response)
  span = OpenTelemetry::Instrumentation::Rack.current_span
  return unless span.recording?

  response_propagators&.each do |propagator|
    propagator.inject(response.headers)
  rescue StandardError => e
    OpenTelemetry.handle_error(message: 'Unable to inject response propagation headers', exception: e)
  end
rescue StandardError => e
  OpenTelemetry.handle_error(exception: e)
end

#on_error(request, _, error) ⇒ Object

Note:

does nothing if the span is a non-recording span

Records Unexpected Exceptions on the Rack span and set the Span Status to Error

Parameters:

  • The (Rack::Request)

    current HTTP request

  • The (Rack::Response)

    current HTTP response

  • An (Exception)

    unxpected error raised by the application



93
94
95
96
97
98
99
100
101
# File 'lib/opentelemetry/instrumentation/rack/middlewares/event_handler.rb', line 93

def on_error(request, _, error)
  span = OpenTelemetry::Instrumentation::Rack.current_span
  return unless span.recording?

  span.record_exception(error)
  span.status = OpenTelemetry::Trace::Status.error(error.class.name)
rescue StandardError => e
  OpenTelemetry.handle_error(exception: e)
end

#on_finish(request, response) ⇒ Object

Note:

does nothing if the span is a non-recording span

Finishes the span making it eligible to be exported and cleans up existing contexts

Parameters:

  • The (Rack::Request)

    current HTTP request

  • The (Rack::Response)

    current HTTP response



108
109
110
111
112
113
114
115
116
117
# File 'lib/opentelemetry/instrumentation/rack/middlewares/event_handler.rb', line 108

def on_finish(request, response)
  span = OpenTelemetry::Instrumentation::Rack.current_span
  return unless span.recording?

  add_response_attributes(span, response) if response
rescue StandardError => e
  OpenTelemetry.handle_error(exception: e)
ensure
  detach_context(request)
end

#on_start(request, _) ⇒ void

This method returns an undefined value.

Creates a server span for this current request using the incoming parent context and registers them as the current_span

Parameters:

  • The (Rack::Request)

    current HTTP request

  • This (Rack::Response)

    is nil in practice



54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/opentelemetry/instrumentation/rack/middlewares/event_handler.rb', line 54

def on_start(request, _)
  parent_context = if untraced_request?(request.env)
                     extract_remote_context(request, OpenTelemetry::Common::Utilities.untraced)
                   else
                     extract_remote_context(request)
                   end

  span = create_span(parent_context, request)
  span_ctx = OpenTelemetry::Trace.context_with_span(span, parent_context: parent_context)
  rack_ctx = OpenTelemetry::Instrumentation::Rack.context_with_span(span, parent_context: span_ctx)
  request.env[OTEL_TOKEN_AND_SPAN] = [OpenTelemetry::Context.attach(rack_ctx), span]
rescue StandardError => e
  OpenTelemetry.handle_error(exception: e)
end