Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change the Redis client patch to use prepend #1743

Merged
merged 1 commit into from
Oct 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions lib/ddtrace/contrib/redis/instrumentation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# typed: false
require 'ddtrace/contrib/patcher'
require 'ddtrace/contrib/redis/ext'
require 'ddtrace/contrib/redis/configuration/resolver'

module Datadog
module Contrib
module Redis
# Instrumentation for Redis
module Instrumentation
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pattern for this module and the patcher module are copied from the http patcher.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fine.

def self.included(base)
base.prepend(InstanceMethods)
end

# InstanceMethods - implementing instrumentation
module InstanceMethods
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code in this module was moved verbatim from the patcher module except for the changes:

  • replaced "without" method calls with super
  • removed calls to alias_method and remove_method

def call(*args, &block)
pin = Datadog::Pin.get_from(self)
return super unless pin && pin.tracer

response = nil
pin.tracer.trace(Datadog::Contrib::Redis::Ext::SPAN_COMMAND) do |span|
span.service = pin.service
span.span_type = Datadog::Contrib::Redis::Ext::TYPE
span.resource = get_command(args)
Datadog::Contrib::Redis::Tags.set_common_tags(self, span)

response = super
end

response
end

def call_pipeline(*args, &block)
pin = Datadog::Pin.get_from(self)
return super unless pin && pin.tracer

response = nil
pin.tracer.trace(Datadog::Contrib::Redis::Ext::SPAN_COMMAND) do |span|
span.service = pin.service
span.span_type = Datadog::Contrib::Redis::Ext::TYPE
commands = get_pipeline_commands(args)
span.resource = commands.join("\n")
span.set_metric Datadog::Contrib::Redis::Ext::METRIC_PIPELINE_LEN, commands.length
Datadog::Contrib::Redis::Tags.set_common_tags(self, span)

response = super
end

response
end

def datadog_pin
@datadog_pin ||= begin
pin = Datadog::Pin.new(
datadog_configuration[:service_name],
app: Ext::APP,
app_type: Datadog::Ext::AppTypes::DB,
tracer: -> { datadog_configuration[:tracer] }
)
pin.onto(self)
end
end

private

def get_command(args)
if datadog_configuration[:command_args]
Datadog::Contrib::Redis::Quantize.format_command_args(*args)
else
Datadog::Contrib::Redis::Quantize.get_verb(*args)
end
end

def get_pipeline_commands(args)
if datadog_configuration[:command_args]
args[0].commands.map { |c| Datadog::Contrib::Redis::Quantize.format_command_args(c) }
else
args[0].commands.map { |c| Datadog::Contrib::Redis::Quantize.get_verb(c) }
end
end

def datadog_configuration
Datadog.configuration[:redis, options]
end
end
end
end
end
end
86 changes: 2 additions & 84 deletions lib/ddtrace/contrib/redis/patcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,92 +23,10 @@ def patch
require 'ddtrace/ext/app_types'
require 'ddtrace/contrib/redis/tags'
require 'ddtrace/contrib/redis/quantize'
require 'ddtrace/contrib/redis/instrumentation'

patch_redis_client
::Redis::Client.include(Instrumentation)
end

# rubocop:disable Metrics/MethodLength
# rubocop:disable Metrics/BlockLength
# rubocop:disable Metrics/AbcSize
def patch_redis_client
::Redis::Client.class_eval do
alias_method :call_without_datadog, :call
remove_method :call
def call(*args, &block)
pin = Datadog::Pin.get_from(self)
return call_without_datadog(*args, &block) unless pin && pin.tracer

response = nil
pin.tracer.trace(Datadog::Contrib::Redis::Ext::SPAN_COMMAND) do |span|
span.service = pin.service
span.span_type = Datadog::Contrib::Redis::Ext::TYPE
span.resource = get_command(args)
Datadog::Contrib::Redis::Tags.set_common_tags(self, span)

response = call_without_datadog(*args, &block)
end

response
end

alias_method :call_pipeline_without_datadog, :call_pipeline
remove_method :call_pipeline
def call_pipeline(*args, &block)
pin = Datadog::Pin.get_from(self)
return call_pipeline_without_datadog(*args, &block) unless pin && pin.tracer

response = nil
pin.tracer.trace(Datadog::Contrib::Redis::Ext::SPAN_COMMAND) do |span|
span.service = pin.service
span.span_type = Datadog::Contrib::Redis::Ext::TYPE
commands = get_pipeline_commands(args)
span.resource = commands.join("\n")
span.set_metric Datadog::Contrib::Redis::Ext::METRIC_PIPELINE_LEN, commands.length
Datadog::Contrib::Redis::Tags.set_common_tags(self, span)

response = call_pipeline_without_datadog(*args, &block)
end

response
end

def datadog_pin
@datadog_pin ||= begin
pin = Datadog::Pin.new(
datadog_configuration[:service_name],
app: Ext::APP,
app_type: Datadog::Ext::AppTypes::DB,
tracer: -> { datadog_configuration[:tracer] }
)
pin.onto(self)
end
end

private

def get_command(args)
if datadog_configuration[:command_args]
Datadog::Contrib::Redis::Quantize.format_command_args(*args)
else
Datadog::Contrib::Redis::Quantize.get_verb(*args)
end
end

def get_pipeline_commands(args)
if datadog_configuration[:command_args]
args[0].commands.map { |c| Datadog::Contrib::Redis::Quantize.format_command_args(c) }
else
args[0].commands.map { |c| Datadog::Contrib::Redis::Quantize.get_verb(c) }
end
end

def datadog_configuration
Datadog.configuration[:redis, options]
end
end
end
# rubocop:enable Metrics/MethodLength
# rubocop:enable Metrics/BlockLength
end
end
end
Expand Down
30 changes: 0 additions & 30 deletions spec/ddtrace/contrib/redis/method_replaced_spec.rb

This file was deleted.

14 changes: 14 additions & 0 deletions spec/ddtrace/contrib/redis/patcher_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# typed: false
require 'ddtrace/contrib/support/spec_helper'
require 'ddtrace'

RSpec.describe Datadog::Contrib::Redis::Patcher do
describe '.patch' do
it 'adds Instrumentation methods to ancestors of Redis class' do
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This spec pattern is from the ethon patch

described_class.patch

expect(Redis::Client.ancestors).to include(Datadog::Contrib::Redis::Instrumentation)
expect(Redis::Client.ancestors).to include(Datadog::Contrib::Redis::Instrumentation)
end
end
end