Class: Appsignal::Rack::AbstractMiddleware Abstract Private

Inherits:
Object
  • Object
show all
Defined in:
lib/appsignal/rack/abstract_middleware.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

This class is abstract.

Base instrumentation middleware.

Do not use this middleware directly. Instead use InstrumentationMiddleware.

Constant Summary collapse

DEFAULT_ERROR_REPORTING =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

:default

Instance Method Summary collapse

Constructor Details

#initialize(app, options = {}) ⇒ AbstractMiddleware

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of AbstractMiddleware.



17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/appsignal/rack/abstract_middleware.rb', line 17

def initialize(app, options = {})
  Appsignal.internal_logger.debug "Initializing #{self.class}"
  @app = app
  @options = options
  @request_class = options.fetch(:request_class, ::Rack::Request)
  @instrument_event_name = options.fetch(:instrument_event_name, nil)
  # The OpenTelemetry instrumentation scope for the request's spans in
  # collector mode. Each framework middleware sets its own; nil falls back
  # to the default scope in the backend.
  @opentelemetry_scope = options.fetch(:opentelemetry_scope, nil)
  @report_errors = options.fetch(:report_errors, DEFAULT_ERROR_REPORTING)
end

Instance Method Details

#call(env) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



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
# File 'lib/appsignal/rack/abstract_middleware.rb', line 30

def call(env)
  if Appsignal.active?
    request = request_for(env)
    # Supported nested instrumentation middlewares by checking if there's
    # already a transaction active for this request.
    wrapped_instrumentation = env.key?(Appsignal::Rack::APPSIGNAL_TRANSACTION)
    transaction =
      if wrapped_instrumentation
        env[Appsignal::Rack::APPSIGNAL_TRANSACTION]
      else
        Appsignal::Transaction.create(
          Appsignal::Transaction::HTTP_REQUEST,
          :opentelemetry_context => Appsignal::OpenTelemetry.extract_rack_context(env),
          :opentelemetry_scope => @opentelemetry_scope
        )
      end

    unless wrapped_instrumentation
      # Set transaction on the request environment so other nested
      # middleware can detect if there is parent instrumentation
      # middleware active.
      env[Appsignal::Rack::APPSIGNAL_TRANSACTION] = transaction
      add_opentelemetry_request_attributes(transaction, request)
    end

    begin
      (transaction, request)
      # Report errors if the :report_errors option is set to true or when
      # there is no parent instrumentation that can rescue and report the error.
      if @report_errors || !wrapped_instrumentation
        instrument_app_call_with_exception_handling(
          request.env,
          transaction,
          wrapped_instrumentation
        )
      else
        instrument_app_call(request.env, transaction)
      end
    ensure
      (transaction, request)

      unless wrapped_instrumentation
        add_opentelemetry_response_attributes(transaction, request)

        # Complete transaction because this is the top instrumentation
        # middleware.
        Appsignal::Transaction.complete_current!
      end
    end
  else
    @app.call(env)
  end
end