# typed: ignore # Copyright (c) 2015 Sqreen. All Rights Reserved. # Please refer to our terms for more information: https://www.sqreen.com/terms.html require 'sqreen/events/remote_exception' require 'sqreen/log/loggable' module Sqreen class EcosystemIntegration # This class gets notified of request start/end and # 1) distributes such events to listeners (typically ecosystem modules; # the method add_start_observer is exposed to ecosystem modules through # +Sqreen::Ecosystem::ModuleApi::EventListener+ and the dispatch table). # 2) keeps track of whether a request is active on this thread. This is # so that users of this class can have this information without needing # to subscribe to request start/events and keeping thread local state # themselves. # XXX: Since the Ecosystem is also notified of request start/end, it could # notify its modules of request start without going through the dispatch # table and call add_start_observer. We need to think if we want to keep # the transaction / request distinction or if they should just be # assumed to be the same, though. class RequestLifecycleTracking include Sqreen::Log::Loggable def initialize @start_observers = [] @tl_key = "#{object_id}_req_in_flight" end # API for classes needing to know the request state # @param cb A callback taking a Rack::Request def add_start_observer(cb) @start_observers << cb end def in_request? Thread.current[@tl_key] ? true : false end # API for classes notifying this one of request events def notify_request_start(rack_req) Thread.current[@tl_key] = true return if @start_observers.empty? @start_observers.each do |cb| begin cb.call(rack_req) rescue ::Exception => e # rubocop:disable Lint/RescueException logger.warn { "Error calling #{cb} on request start: #{e.message}" } Sqreen::RemoteException.record(e) end end end def notify_request_end Thread.current[@tl_key] = false end end end end