module NewRelic::Agent::Instrumentation::Elasticsearch
Constants
- INSTANCE_METHOD_PATTERN
-
Use the
OPERATION_PATTERN
pattern to find the appropriate caller location that will contain the client instance method (example: ‘search’) and return that method name.A Ruby caller location matching the
OPERATION_PATTERN
will contain an elasticsearch client instance method name (such as “search”), and that method name will be used as the operation name.With Ruby < 3.4 the method name is listed as:
`search'
with an opening backtick and a closing single tick. And only the method name itself is listed.
With Ruby 3.4+ the method name is listed as:
'Elasticsearch::API::Actions#search'
with opening and closing single ticks and the class defining the instance method listed.
(?:) = ?: prevents capturing (?:‘|’) = allow ‘ or ’ (?:.+#) = allow the class name and ‘#’ prefix to exist but ignore it ([^‘]+)’ = after the opening ‘ or ’, capturing everything up to the
closing '. [^']+ = one or more characters that are not '
Example Ruby 3.3.1 input:
/Users/fallwith/.rubies/ruby-3.3.1/lib/ruby/gems/3.3.0/gems/elasticsearch-api-7.17.10/lib/elasticsearch/api/actions/index.rb:74:in `index'
Example Ruby 3.4.0-preview1 input:
/Users/fallwith/.rubies/ruby-3.4.0-preview1/lib/ruby/gems/3.4.0+0/gems/elasticsearch-api-7.17.10/lib/elasticsearch/api/actions/index.rb:74:in 'Elasticsearch::API::Actions#index'
Example output for both Rubies:
index
- INSTRUMENTATION_NAME
- OPERATION
- OPERATION_PATTERN
-
Pattern to use with client caller location strings. Look for a location that contains ‘/lib/elasticsearch/api/’ and is NOT followed by the string held in the
OPERATION
constant - PRODUCT_NAME
Public Instance Methods
Source
# File lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb, line 65 def perform_request_with_tracing(_method, _path, params = {}, body = nil, _headers = nil, *_args) return yield unless NewRelic::Agent::Tracer.tracing_enabled? NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME) segment = NewRelic::Agent::Tracer.start_datastore_segment( product: PRODUCT_NAME, operation: nr_operation || OPERATION, host: nr_hosts[:host], port_path_or_id: nr_hosts[:port], database_name: nr_cluster_name ) begin NewRelic::Agent::Tracer.capture_segment_error(segment) { yield } ensure if segment segment.notice_nosql_statement(nr_reported_query(body || params)) segment.finish end end end
We need the positional arguments ‘params` and `body` to capture the nosql statement *args protects the instrumented method if new arguments are added to perform_request
Private Instance Methods
Source
# File lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb, line 104 def nr_cluster_name return unless NewRelic::Agent.config[:'elasticsearch.capture_cluster_name'] return @nr_cluster_name if defined?(@nr_cluster_name) return if nr_hosts.empty? NewRelic::Agent.disable_all_tracing do @nr_cluster_name ||= perform_request('GET', '/').body['cluster_name'] end rescue StandardError => e NewRelic::Agent.logger.error('Failed to get cluster name for elasticsearch', e) nil end
Source
# File lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb, line 117 def nr_hosts @nr_hosts ||= (transport.hosts.first || NewRelic::EMPTY_HASH) end
Source
# File lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb, line 90 def nr_operation location = caller_locations.detect { |loc| loc.to_s.match?(OPERATION_PATTERN) } return unless location && location.to_s =~ INSTANCE_METHOD_PATTERN Regexp.last_match(1) end
Source
# File lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb, line 97 def nr_reported_query(query) return unless NewRelic::Agent.config[:'elasticsearch.capture_queries'] return query unless NewRelic::Agent.config[:'elasticsearch.obfuscate_queries'] NewRelic::Agent::Datastores::NosqlObfuscator.obfuscate_statement(query) end