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

Update Elasticsearch patcher from using alias method to prepend method #3030

Merged
merged 2 commits into from
Aug 14, 2023
Merged
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
201 changes: 99 additions & 102 deletions lib/datadog/tracing/contrib/elasticsearch/patcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,123 +24,120 @@ def patch
require 'json'
require_relative 'quantize'

patch_elasticsearch_transport_client
transport_module::Client.prepend(Client)
end

SELF_DEPRECATION_ONLY_ONCE = Core::Utils::OnlyOnce.new

# rubocop:disable Metrics/MethodLength
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
def patch_elasticsearch_transport_client
# rubocop:disable Metrics/BlockLength
transport_module::Client.class_eval do
alias_method :perform_request_without_datadog, :perform_request
remove_method :perform_request

def perform_request(*args)
# DEV-2.0: Remove this access, as `Client#self` in this context is not exposed to the user
# since `elasticsearch` v8.0.0. In contrast, `Client#transport` is always available across
# all `elasticsearch` gem versions and should be used instead.
service = Datadog.configuration_for(self, :service_name)

if service
SELF_DEPRECATION_ONLY_ONCE.run do
Datadog.logger.warn(
'Providing configuration though the Elasticsearch client object is deprecated.' \
'Configure the `client#transport` object instead: ' \
'Datadog.configure_onto(client.transport, service_name: service_name, ...)'
# Patches Elasticsearch::Transport::Client module
module Client
# rubocop:disable Metrics/MethodLength
# rubocop:disable Metrics/AbcSize
def perform_request(*args)
# DEV-2.0: Remove this access, as `Client#self` in this context is not exposed to the user
# since `elasticsearch` v8.0.0. In contrast, `Client#transport` is always available across
# all `elasticsearch` gem versions and should be used instead.
service = Datadog.configuration_for(self, :service_name)

if service
SELF_DEPRECATION_ONLY_ONCE.run do
Datadog.logger.warn(
'Providing configuration though the Elasticsearch client object is deprecated.' \
'Configure the `client#transport` object instead: ' \
'Datadog.configure_onto(client.transport, service_name: service_name, ...)'
)
end
end

# `Client#transport` is most convenient object both this integration and the library
# user have shared access to across all `elasticsearch` versions.
#
# `Client#self` in this context is an internal object that the library user
# does not have access to since `elasticsearch` v8.0.0.
service ||= Datadog.configuration_for(transport, :service_name) || datadog_configuration[:service_name]

method = args[0]
path = args[1]
params = args[2]
body = args[3]
full_url = URI.parse(path)
url = full_url.path
response = nil

Tracing.trace(Datadog::Tracing::Contrib::Elasticsearch::Ext::SPAN_QUERY, service: service) do |span|
begin
connection = transport.connections.first
host = connection.host[:host] if connection
port = connection.host[:port] if connection

if datadog_configuration[:peer_service]
span.set_tag(
Tracing::Metadata::Ext::TAG_PEER_SERVICE,
datadog_configuration[:peer_service]
)
end
end

# `Client#transport` is most convenient object both this integration and the library
# user have shared access to across all `elasticsearch` versions.
#
# `Client#self` in this context is an internal object that the library user
# does not have access to since `elasticsearch` v8.0.0.
service ||= Datadog.configuration_for(transport, :service_name) || datadog_configuration[:service_name]

method = args[0]
path = args[1]
params = args[2]
body = args[3]
full_url = URI.parse(path)

url = full_url.path
response = nil

Tracing.trace(Datadog::Tracing::Contrib::Elasticsearch::Ext::SPAN_QUERY, service: service) do |span|
begin
connection = transport.connections.first
host = connection.host[:host] if connection
port = connection.host[:port] if connection

if datadog_configuration[:peer_service]
span.set_tag(
Tracing::Metadata::Ext::TAG_PEER_SERVICE,
datadog_configuration[:peer_service]
)
end

span.span_type = Datadog::Tracing::Contrib::Elasticsearch::Ext::SPAN_TYPE_QUERY

span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_QUERY)
span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_CLIENT)

span.set_tag(Contrib::Ext::DB::TAG_SYSTEM, Ext::TAG_SYSTEM)

# load JSON for the following fields unless they're already strings
params = JSON.generate(params) if params && !params.is_a?(String)
body = JSON.generate(body) if body && !body.is_a?(String)

span.set_tag(Tracing::Metadata::Ext::TAG_PEER_HOSTNAME, host) if host

# Set analytics sample rate
if Contrib::Analytics.enabled?(datadog_configuration[:analytics_enabled])
Contrib::Analytics.set_sample_rate(span, datadog_configuration[:analytics_sample_rate])
end

span.set_tag(Datadog::Tracing::Contrib::Elasticsearch::Ext::TAG_METHOD, method)
span.set_tag(Datadog::Tracing::Contrib::Elasticsearch::Ext::TAG_URL, url)
span.set_tag(Datadog::Tracing::Contrib::Elasticsearch::Ext::TAG_PARAMS, params) if params
if body
quantize_options = datadog_configuration[:quantize]
quantized_body = Datadog::Tracing::Contrib::Elasticsearch::Quantize.format_body(
body,
quantize_options
)
span.set_tag(Datadog::Tracing::Contrib::Elasticsearch::Ext::TAG_BODY, quantized_body)
end
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, host) if host
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, port) if port

quantized_url = Datadog::Tracing::Contrib::Elasticsearch::Quantize.format_url(url)
span.resource = "#{method} #{quantized_url}"
Contrib::SpanAttributeSchema.set_peer_service!(span, Ext::PEER_SERVICE_SOURCES)
rescue StandardError => e
Datadog.logger.error(e.message)
ensure
# the call is still executed
response = perform_request_without_datadog(*args)
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE, response.status)
span.span_type = Datadog::Tracing::Contrib::Elasticsearch::Ext::SPAN_TYPE_QUERY

span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_QUERY)
span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_CLIENT)

span.set_tag(Contrib::Ext::DB::TAG_SYSTEM, Ext::TAG_SYSTEM)

span.set_tag(Tracing::Metadata::Ext::TAG_PEER_HOSTNAME, host) if host

# Set analytics sample rate
if Contrib::Analytics.enabled?(datadog_configuration[:analytics_enabled])
Contrib::Analytics.set_sample_rate(span, datadog_configuration[:analytics_sample_rate])
end

span.set_tag(Datadog::Tracing::Contrib::Elasticsearch::Ext::TAG_METHOD, method)
tag_params(params, span)
tag_body(body, span)
span.set_tag(Datadog::Tracing::Contrib::Elasticsearch::Ext::TAG_URL, url)
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, host) if host
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, port) if port

quantized_url = Datadog::Tracing::Contrib::Elasticsearch::Quantize.format_url(url)
span.resource = "#{method} #{quantized_url}"
Contrib::SpanAttributeSchema.set_peer_service!(span, Ext::PEER_SERVICE_SOURCES)
rescue StandardError => e
Datadog.logger.error(e.message)
ensure
# the call is still executed
response = super
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE, response.status)
end
response
end
response
end

def datadog_configuration
Datadog.configuration.tracing[:elasticsearch]
end
def tag_params(params, span)
return unless params

params = JSON.generate(params) unless params.is_a?(String)
span.set_tag(Datadog::Tracing::Contrib::Elasticsearch::Ext::TAG_PARAMS, params)
end

def tag_body(body, span)
return unless body

body = JSON.generate(body) unless body.is_a?(String)
quantize_options = datadog_configuration[:quantize]
quantized_body = Datadog::Tracing::Contrib::Elasticsearch::Quantize.format_body(
body,
quantize_options
)
span.set_tag(Datadog::Tracing::Contrib::Elasticsearch::Ext::TAG_BODY, quantized_body)
end

def datadog_configuration
Datadog.configuration.tracing[:elasticsearch]
end
# rubocop:enable Metrics/BlockLength
end
# rubocop:enable Metrics/MethodLength
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/PerceivedComplexity

# `Elasticsearch` namespace renamed to `Elastic` in version 8.0.0 of the transport gem:
# @see https://github.com/elastic/elastic-transport-ruby/commit/ef804cbbd284f2a82d825221f87124f8b5ff823c
Expand Down
Loading