module OpenTelemetry::Instrumentation::Redis::Patches::Client

Module to prepend to Redis::Client for instrumentation

Constants

MAX_STATEMENT_LENGTH

Public Instance Methods

process(commands) click to toggle source
Calls superclass method
# File lib/opentelemetry/instrumentation/redis/patches/client.rb, line 16
def process(commands) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
  return super unless config[:trace_root_spans] || OpenTelemetry::Trace.current_span.context.valid?

  host = options[:host]
  port = options[:port]

  attributes = {
    'db.system' => 'redis',
    'net.peer.name' => host,
    'net.peer.port' => port
  }

  attributes['db.redis.database_index'] = options[:db] unless options[:db].zero?
  attributes['peer.service'] = config[:peer_service] if config[:peer_service]
  attributes.merge!(OpenTelemetry::Instrumentation::Redis.attributes)

  unless config[:db_statement] == :omit
    parsed_commands = parse_commands(commands)
    parsed_commands = OpenTelemetry::Common::Utilities.truncate(parsed_commands, MAX_STATEMENT_LENGTH)
    parsed_commands = OpenTelemetry::Common::Utilities.utf8_encode(parsed_commands, binary: true)
    attributes['db.statement'] = parsed_commands
  end

  span_name = if commands.length == 1
                commands[0][0].to_s.upcase
              else
                'PIPELINED'
              end

  tracer.in_span(span_name, attributes: attributes, kind: :client) do |s|
    super(commands).tap do |reply|
      if reply.is_a?(::Redis::CommandError)
        s.record_exception(reply)
        s.status = Trace::Status.error(reply.message)
      end
    end
  end
end

Private Instance Methods

config() click to toggle source
# File lib/opentelemetry/instrumentation/redis/patches/client.rb, line 87
def config
  Redis::Instrumentation.instance.config
end
parse_commands(commands) click to toggle source

Examples of commands received for parsing Redis#queue [[[:set, “v1”, “0”]], [[:incr, “v1”]], [[:get, “v1”]]] Redis#pipeline: [[:set, “v1”, “0”], [:incr, “v1”], [:get, “v1”]] Redis#hmset [[:hmset, “hash”, “f1”, 1234567890.0987654]] Redis#set [[:set, “K”, “x”]]

# File lib/opentelemetry/instrumentation/redis/patches/client.rb, line 62
def parse_commands(commands) # rubocop:disable Metrics/AbcSize
  commands.map do |command|
    # We are checking for the use of Redis#queue command, if we detect the
    # extra level of array nesting we return the first element so it
    # can be parsed.
    command = command[0] if command.is_a?(Array) && command[0].is_a?(Array)

    # If we receive an authentication request command
    # we want to short circuit parsing the commands
    # and return the obfuscated command
    return 'AUTH ?' if command[0] == :auth

    command[0] = command[0].to_s.upcase
    if config[:db_statement] == :obfuscate
      command[0] + ' ?' * (command.size - 1)
    else
      command.join(' ')
    end
  end.join("\n")
end
tracer() click to toggle source
# File lib/opentelemetry/instrumentation/redis/patches/client.rb, line 83
def tracer
  Redis::Instrumentation.instance.tracer
end