# encoding: utf-8 require 'one_apm/agent/datastore/metric_helper' module OneApm module Agent module Instrumentation module Memcache module_function def enabled? !OneApm::Manager.config[:disable_memcache] end OA_METHODS = [:get, :get_multi, :set, :add, :incr, :decr, :delete, :replace, :append, :prepend, :cas, :single_get, :multi_get, :single_cas, :multi_cas] def supported_methods_for(client_class, methods) methods.select do |method_name| client_class.method_defined?(method_name) || client_class.private_method_defined?(method_name) end end def instrument_methods(client_class, requested_methods = OA_METHODS) supported_methods_for(client_class, requested_methods).each do |method_name| visibility = OneApm::Helper.instance_method_visibility client_class, method_name method_name_without = :"#{method_name}_without_oneapm_trace" client_class.class_eval do alias_method method_name_without, method_name if defined?(::MemCache) def oneapm_product @product ||= begin s = Array(servers) host, port = s.first.host, s.first.port if s.first rescue nil OneApm::Agent::Datastore.oneapm_product("Memcached", host, port) end end private :oneapm_product else def oneapm_product @product ||= begin s = Array(@servers || servers) host, port, weight = s.first.split(":") if s.first && s.first.to_s.include?(':') rescue nil OneApm::Agent::Datastore.oneapm_product("Memcached", host, port) end end private :oneapm_product end define_method method_name do |*args, &block| metrics = Datastore::MetricHelper.metrics_for(oneapm_product, method_name) OneApm::Support::MethodTracer.trace_execution_scoped(metrics) do t0 = Time.now begin send method_name_without, *args, &block ensure if OneApm::Manager.config[:capture_memcache_keys] OneApm::Manager.agent.transaction_sampler.notice_nosql(args.first.inspect, (Time.now - t0).to_f) rescue nil end end end end send visibility, method_name send visibility, method_name_without end end end end end end end LibraryDetection.defer do named :memcache_client depends_on do OneApm::Agent::Instrumentation::Memcache.enabled? end depends_on do defined?(::MemCache) end executes do OneApm::Manager.logger.info 'Installing Memcached instrumentation for memcache-client gem' OneApm::Agent::Instrumentation::Memcache.instrument_methods(::MemCache) end end LibraryDetection.defer do named :memcached depends_on do OneApm::Agent::Instrumentation::Memcache.enabled? end depends_on do defined?(::Memcached) end executes do OneApm::Manager.logger.info 'Installing Memcached instrumentation for memcached gem' ::OneApm::Agent::Instrumentation::Memcache.instrument_methods(::Memcached) end end LibraryDetection.defer do named :dalli depends_on do OneApm::Agent::Instrumentation::Memcache.enabled? end depends_on do defined?(::Dalli::Client) end executes do OneApm::Manager.logger.info 'Installing Memcache instrumentation for dalli gem' ::OneApm::Agent::Instrumentation::Memcache.instrument_methods(::Dalli::Client) end end LibraryDetection.defer do named :dalli_cas_client depends_on do OneApm::Agent::Instrumentation::Memcache.enabled? end depends_on do # These CAS client methods are only optionally defined if users require # dalli/cas/client. Use a separate dependency block so it can potentially # re-evaluate after they've done that require. defined?(::Dalli::Client) && ::OneApm::Agent::Instrumentation::Memcache.supported_methods_for(::Dalli::Client, OA_CAS_CLIENT_METHODS).any? end OA_CAS_CLIENT_METHODS = [:get_cas, :get_multi_cas, :set_cas, :replace_cas, :delete_cas] executes do OneApm::Manager.logger.info 'Installing Dalli CAS Client Memcache instrumentation' ::OneApm::Agent::Instrumentation::Memcache.instrument_methods(::Dalli::Client, OA_CAS_CLIENT_METHODS) end end