appsignal/appsignal

View on GitHub
lib/appsignal/integrations/padrino.rb

Summary

Maintainability
A
55 mins
Test Coverage
# frozen_string_literal: true

require "appsignal"

module Appsignal
  module Integrations
    # @api private
    module PadrinoPlugin
      def self.init
        Appsignal.logger.info("Loading Padrino (#{Padrino::VERSION}) integration")

        root = Padrino.mounted_root
        Appsignal.config = Appsignal::Config.new(root, Padrino.env)

        Appsignal.start_logger
        Appsignal.start
      end
    end
  end
end

module Padrino::Routing::InstanceMethods
  alias route_without_appsignal route!

  def route!(base = settings, pass_block = nil)
    if !Appsignal.active? || env["sinatra.static_file"]
      return route_without_appsignal(base, pass_block)
    end

    transaction = Appsignal::Transaction.create(
      SecureRandom.uuid,
      Appsignal::Transaction::HTTP_REQUEST,
      request
    )
    begin
      Appsignal.instrument("process_action.padrino") do
        route_without_appsignal(base, pass_block)
      end
    rescue Exception => error # rubocop:disable Lint/RescueException
      transaction.set_error(error)
      raise error
    ensure
      transaction.set_action_if_nil(get_payload_action(request))
      transaction.set_metadata("path", request.path)
      transaction.set_metadata("method", request.request_method)
      transaction.set_http_or_background_queue_start
      Appsignal::Transaction.complete_current!
    end
  end

  private

  def get_payload_action(request)
    # Short-circut is there's no request object to obtain information from
    return settings.name.to_s unless request

    # Newer versions expose the action / controller on the request class.
    # Newer versions also still expose a route_obj so we must prioritize the
    # action/fullpath methods.
    # The `request.action` and `request.controller` values are `nil` when a
    # endpoint is not found, `""` if not specified by the user.
    controller_name = request.controller if request.respond_to?(:controller)
    action_name = request.action if request.respond_to?(:action)
    action_name ||= ""

    unless action_name.empty?
      return "#{settings.name}:#{controller_name}##{action_name}"
    end

    # Older versions of Padrino work with a route object
    if request.respond_to?(:route_obj) && request.route_obj
      return "#{settings.name}:#{request.route_obj.original_path}"
    end

    # Fall back to the application name if we haven't found an action name in
    # any previous methods.
    "#{settings.name}#unknown"
  end
end

Padrino.after_load do
  Appsignal::Integrations::PadrinoPlugin.init
end