# encoding: utf-8 require 'one_apm/support/parameter_filtering' module OneApm module Agent module Instrumentation module Grape extend self API_ENDPOINT = 'api.endpoint'.freeze FORMAT_REGEX = /\(\/?\.(:format|json)?\)/.freeze VERSION_REGEX = /:version(\/|$)/.freeze EMPTY_STRING = ''.freeze MIN_VERSION = VersionNumber.new('0.2.0') def handle_transaction(endpoint, class_name) return unless endpoint && route = endpoint.route name_transaction(route, class_name) capture_params(endpoint) if OneApm::Manager.config[:capture_params] end def name_transaction(route, class_name) txn_name = name_for_transaction(route, class_name) segment_name = "Middleware/Grape/#{class_name}/call" Transaction.set_default_transaction_name(txn_name, :grape, segment_name) end def name_for_transaction(route, class_name) route_path, route_method, route_version = path_method_version_of(route) action_name = route_path.sub(FORMAT_REGEX, EMPTY_STRING) method_name = route_method if route_version action_name = action_name.sub(VERSION_REGEX, EMPTY_STRING) "#{class_name}-#{route_version}#{action_name} (#{method_name})" else "#{class_name}#{action_name} (#{method_name})" end end if defined?(::Grape::VERSION) && VersionNumber.new(::Grape::VERSION) >= VersionNumber.new('0.16.0') def path_method_version_of(route) [route.path, route.request_method, route.version] end else def path_method_version_of(route) [route.route_path, route.route_method, route.route_version] end end def capture_params(endpoint) txn = Transaction.tl_current env = endpoint.request.env params = OneApm::Support::ParameterFiltering::apply_filters(env, endpoint.params) params.delete("route_info") txn.filtered_params = params end end end end end LibraryDetection.defer do # Why not just :grape? oneapm-grape used that name already, and while we're # not shipping yet, overloading the name interferes with the plugin. named :grape depends_on do OneApm::Manager.config[:disable_grape] == false end depends_on do defined?(::Grape::VERSION) && ::OneApm::VersionNumber.new(::Grape::VERSION) >= ::OneApm::Agent::Instrumentation::Grape::MIN_VERSION end executes do OneApm::Manager.logger.info 'Installing Grape instrumentation' instrument_call end def instrument_call ::Grape::API.class_eval do def call_with_one_apm(env) begin response = call_without_one_apm(env) ensure begin endpoint = env[::OneApm::Agent::Instrumentation::Grape::API_ENDPOINT] ::OneApm::Agent::Instrumentation::Grape.handle_transaction(endpoint, self.class.name) rescue => e OneApm::Manager.logger.warn("Error in Grape instrumentation", e) end end response end alias_method :call_without_one_apm, :call alias_method :call, :call_with_one_apm end end end