# encoding: utf-8 require 'one_apm/support/method_tracer' LibraryDetection.defer do @name = :redis depends_on do defined?(::Redis) && !OneApm::Manager.config[:disable_redis] end executes do OneApm::Manager.logger.info 'Installing Redis Instrumentation' end executes do require 'one_apm/agent/datastore' ::Redis::Client.class_eval do # Support older versions of Redis::Client that used the method # +raw_call_command+. call_method = ::Redis::Client.new.respond_to?(:call) ? :call : :raw_call_command def call_with_oneapm_trace(*args, &blk) method_name = args[0].is_a?(Array) ? args[0][0] : args[0] filtered_command = filter method_name callback = proc do |result, metric, elapsed| _send_to_one_apm(args, elapsed) end OneApm::Agent::Datastore.wrap("Redis", filtered_command, nil, callback) do call_without_oneapm_trace(*args, &blk) end end alias_method :call_without_oneapm_trace, call_method alias_method call_method, :call_with_oneapm_trace # Older versions of Redis handle pipelining completely differently. # Don't bother supporting them for now. # if public_method_defined? :call_pipelined def call_pipelined_with_oneapm_trace(commands, *rest) # Report each command as a metric suffixed with _pipelined, so the # user can at least see what all the commands were. additional = commands.map do |c| name = c.kind_of?(Array) ? c[0] : c "Datastore/operation/Redis/#{name.to_s.downcase}_pipelined" end callback = proc do |result, metric, elapsed| _send_to_one_apm(commands, elapsed) additional.each do |additional_metric| OneApm::Support::MethodTracer.trace_execution_scoped(additional_metric) do # No-op, just getting them as placeholders in the trace tree end end end OneApm::Agent::Datastore.wrap("Redis", "pipelined", nil, callback) do call_pipelined_without_oneapm_trace commands, *rest end end alias_method :call_pipelined_without_oneapm_trace, :call_pipelined alias_method :call_pipelined, :call_pipelined_with_oneapm_trace end def _send_to_one_apm(args, elapsed) if OneApm::Manager.config[:"transaction_tracer.record_sql"] == "obfuscated" args.map! do |arg| if arg.empty? arg else [arg.first] + ["?"] * (arg.count - 1) end end end OneApm::Agent::Datastore.notice_statement(args.inspect, elapsed) end def filter command need_filtered = OneApm::Manager.config[:'redis.ignore_commands'].map(&:to_s).include?(command.to_s) if need_filtered OneApm::Manager.logger.debug "filter command: #{command}" nil else command end end end end end