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

OpenSearch instrumentation #2796

Merged
merged 45 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
0b1cf2c
Merge pull request #2726 from newrelic/dev
fallwith Jun 20, 2024
fa1462f
Initial commit for OpenSearch instrumentation
kaylareopelle Aug 7, 2024
f11602b
Draft opensearch service for CI
kaylareopelle Aug 7, 2024
c9cd857
Adjust test environment for opensearch
kaylareopelle Aug 7, 2024
bd239ac
Fix spacing
kaylareopelle Aug 7, 2024
8f6b709
Small updates to docker-compose and ci_cron
kaylareopelle Aug 7, 2024
7194bd0
Remove unnecessary ::
kaylareopelle Aug 7, 2024
dd1f09f
Update images for opensearch ci services
kaylareopelle Aug 7, 2024
7e4ba64
Update opensearch version
kaylareopelle Aug 7, 2024
430d6ba
disable security plugins
kaylareopelle Aug 7, 2024
314ea59
disable demo config
kaylareopelle Aug 7, 2024
77094d6
Remove options
kaylareopelle Aug 7, 2024
737c2b9
Simplify opensearch ci.yml service
kaylareopelle Aug 7, 2024
d2adc1e
Add details for health check
kaylareopelle Aug 8, 2024
3e66700
Adjust opensearch ci service
kaylareopelle Aug 8, 2024
e95edfb
Remove other services for faster feedback
kaylareopelle Aug 8, 2024
4a9f08c
Add some services back
kaylareopelle Aug 8, 2024
ad099e6
Fix test port
kaylareopelle Aug 8, 2024
bc556fa
Remove security disabling
kaylareopelle Aug 8, 2024
b496be3
Add security disable configs back to opensearch
kaylareopelle Aug 9, 2024
82078ae
try removing demo config only
kaylareopelle Aug 9, 2024
b8e52ad
Revert
kaylareopelle Aug 9, 2024
2304b1a
Push the version
kaylareopelle Aug 9, 2024
27e3a0d
update to match docker-rails and searchkick
kaylareopelle Aug 9, 2024
2c9b460
rubocop
kaylareopelle Aug 9, 2024
d726f3c
Revert to what works locally
kaylareopelle Aug 9, 2024
4dac92a
Try to connect to elasticsearch
kaylareopelle Aug 9, 2024
fdd258c
Downgrade to 7.10 elasticsearch
kaylareopelle Aug 9, 2024
cede740
Update elasticsearch7 image to 7.10.1
kaylareopelle Aug 9, 2024
ab3b26f
Run tests on older opensearch
kaylareopelle Aug 9, 2024
c5c9413
Run only 'rest'
kaylareopelle Aug 9, 2024
3bdacb0
Opensearch 2 CI action step
kaylareopelle Aug 9, 2024
d186de4
only opensearch
kaylareopelle Aug 9, 2024
e86cbcf
fix error
kaylareopelle Aug 9, 2024
e007242
Add 2.4 back
kaylareopelle Aug 9, 2024
9dcb6ad
Cleanup post-CI
kaylareopelle Aug 9, 2024
39a6758
Make 'true' a string in suite condition
kaylareopelle Aug 9, 2024
a90fe02
Merge branch 'main' into opensearch-instrumentation
kaylareopelle Aug 9, 2024
7ea4df9
Merge branch 'dev' into opensearch-instrumentation
kaylareopelle Aug 9, 2024
9f26446
Add OpenSearch changelog entry
kaylareopelle Aug 9, 2024
0f77f60
Add a 2.4-compatible version to the gemspec
kaylareopelle Aug 12, 2024
53b2fe4
Update docker-compose.yml
kaylareopelle Aug 12, 2024
665d621
Revert changes to instrumentation generator
kaylareopelle Aug 12, 2024
1e09324
Merge branch 'opensearch-instrumentation' of github.com:newrelic/newr…
kaylareopelle Aug 12, 2024
35b1090
Update argument defaults to reduce object alloc
kaylareopelle Aug 12, 2024
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
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

## dev

Version <dev> updates framework detection, fixes Falcon dispatcher detection, and addresses a JRuby specific concurrency issue.
Version <dev> adds experimental OpenSearch instrumentation, updates framework detection, fixes Falcon dispatcher detection, and addresses a JRuby specific concurrency issue.

- **Feature: Add experimental OpenSearch instrumentation**

The agent will now automatically instrument the `opensearch-ruby` gem. We're marking this instrumentation as experimental because more work is needed to fully test it. OpenSearch instrumentation provides telemetry similar to Elasticsearch. Thank you, [@Earlopain](https://github.com/Earlopain) for reporting the issue and [@praveen-ks](https://github.com/praveen-ks) for an initial draft of the instrumentation. [Issue#2228](https://github.com/newrelic/newrelic-ruby-agent/issues/2228) [PR#2796](https://github.com/newrelic/newrelic-ruby-agent/pull/2796)

- **Feature: Improve framework detection accuracy for Grape and Padrino**

Expand Down
13 changes: 12 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
version: "3.9"
services:
elasticsearch7:
image: elasticsearch:7.16.2
Expand All @@ -20,6 +19,17 @@ services:
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
mem_limit: 1g
# this docker-compose service doesn't always work with "docker compose run opensearch"
# the tests consistently work with:
# docker run -it -p 9200:9200 -p 9600:9600 -e "discovery.type=single-node" --name opensearch-node opensearchproject/opensearch:1.3.18
# opensearch:
# image: opensearchproject/opensearch:1.3.18
# environment:
# - discovery.type=single-node
# ports:
# - 9200:9200
# - 9600:9600
# mem_limit: 1g
mysql:
image: mysql:5.7
platform: linux/x86_64
Expand Down Expand Up @@ -91,6 +101,7 @@ services:
depends_on:
- elasticsearch7
- elasticsearch8
- opensearch
- mysql
- memcached
- mongodb
Expand Down
24 changes: 24 additions & 0 deletions lib/new_relic/agent/configuration/default_source.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1463,6 +1463,15 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil)
:allowed_from_server => false,
:description => 'Controls auto-instrumentation of bunny at start-up. May be one of: `auto`, `prepend`, `chain`, `disabled`.'
},
:'instrumentation.opensearch' => {
kaylareopelle marked this conversation as resolved.
Show resolved Hide resolved
:default => 'auto',
:documentation_default => 'auto',
:public => true,
:type => String,
:dynamic_name => true,
:allowed_from_server => false,
:description => 'Controls auto-instrumentation of the opensearch-ruby library at start-up. May be one of `auto`, `prepend`, `chain`, `disabled`.'
},
:'instrumentation.aws_sqs' => {
:default => 'auto',
:public => true,
Expand Down Expand Up @@ -1870,6 +1879,21 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil)
:allowed_from_server => true,
:description => 'If `true`, the agent obfuscates Mongo queries in transaction traces.'
},
# OpenSearch
:'opensearch.capture_queries' => {
:default => true,
:public => true,
:type => Boolean,
:allowed_from_server => true,
:description => 'If `true`, the agent captures OpenSearch queries in transaction traces.'
},
:'opensearch.obfuscate_queries' => {
:default => true,
:public => true,
:type => Boolean,
:allowed_from_server => true,
:description => 'If `true`, the agent obfuscates OpenSearch queries in transaction traces.'
},
# Process host
:'process_host.display_name' => {
:default => proc { NewRelic::Agent::Hostname.get },
Expand Down
25 changes: 25 additions & 0 deletions lib/new_relic/agent/instrumentation/opensearch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# This file is distributed under New Relic's license terms.
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
# frozen_string_literal: true

require_relative 'opensearch/instrumentation'
require_relative 'opensearch/chain'
require_relative 'opensearch/prepend'

DependencyDetection.defer do
named :opensearch

depends_on do
defined?(OpenSearch)
kaylareopelle marked this conversation as resolved.
Show resolved Hide resolved
end

executes do
NewRelic::Agent.logger.info('Installing opensearch-ruby instrumentation')

if use_prepend?
prepend_instrument OpenSearch::Transport::Client, NewRelic::Agent::Instrumentation::OpenSearch::Prepend
else
chain_instrument NewRelic::Agent::Instrumentation::OpenSearch::Chain
end
end
end
21 changes: 21 additions & 0 deletions lib/new_relic/agent/instrumentation/opensearch/chain.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# This file is distributed under New Relic's license terms.
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
# frozen_string_literal: true

module NewRelic::Agent::Instrumentation
module OpenSearch::Chain
def self.instrument!
::OpenSearch::Transport::Client.class_eval do
include NewRelic::Agent::Instrumentation::OpenSearch

alias_method(:perform_request_without_tracing, :perform_request)

def perform_request(*args)
perform_request_with_tracing(*args) do
perform_request_without_tracing(*args)
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# This file is distributed under New Relic's license terms.
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
# frozen_string_literal: true

module NewRelic::Agent::Instrumentation
module OpenSearch
PRODUCT_NAME = 'OpenSearch'
OPERATION = 'perform_request'
OPERATION_PATTERN = %r{/lib/opensearch/api/(?!.+#{OPERATION})}
INSTANCE_METHOD_PATTERN = /:in (?:`|')(?:.+#)?([^']+)'\z/
INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)

def perform_request_with_tracing(_method, _path, params = {}, body = nil, _headers = nil, _opts = {}, &_block)
kaylareopelle marked this conversation as resolved.
Show resolved Hide resolved
return yield unless NewRelic::Agent::Tracer.tracing_enabled?

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

private

# See Elasticsearch instrumentation for explanation on Ruby 3.4 changes to match instance method
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

def nr_reported_query(query)
return unless NewRelic::Agent.config[:'opensearch.capture_queries']
return query unless NewRelic::Agent.config[:'opensearch.obfuscate_queries']

NewRelic::Agent::Datastores::NosqlObfuscator.obfuscate_statement(query)
end

def nr_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 OpenSearch', e)
nil
end

def nr_hosts
@nr_hosts ||= (transport.hosts.first || NewRelic::EMPTY_HASH)
end
end
end
13 changes: 13 additions & 0 deletions lib/new_relic/agent/instrumentation/opensearch/prepend.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# This file is distributed under New Relic's license terms.
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
# frozen_string_literal: true

module NewRelic::Agent::Instrumentation
module OpenSearch::Prepend
include NewRelic::Agent::Instrumentation::OpenSearch

def perform_request(*args)
perform_request_with_tracing(*args) { super }
end
end
end
2 changes: 1 addition & 1 deletion lib/tasks/instrumentation_generator/instrumentation.thor
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class Instrumentation < Thor
<<-CONFIG
:'instrumentation.#{snake_name}' => {
:default => 'auto',
:documentation_default => 'auto'
:documentation_default => 'auto',
:public => true,
:type => String,
:dynamic_name => true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ DependencyDetection.defer do
depends_on do
# The class that needs to be defined to prepend/chain onto. This can be used
# to determine whether the library is installed.
defined?(::<%= @class_name %>)
defined?(<%= @class_name %>)
kaylareopelle marked this conversation as resolved.
Show resolved Hide resolved
# Add any additional requirements to verify whether this instrumentation
# should be installed
end

executes do
::NewRelic::Agent.logger.info('Installing <%= @name.downcase %> instrumentation')
NewRelic::Agent.logger.info('Installing <%= @name.downcase %> instrumentation')

if use_prepend?
prepend_instrument ::<%= @class_name %>, NewRelic::Agent::Instrumentation::<%= @class_name %>::Prepend
prepend_instrument <%= @class_name %>, NewRelic::Agent::Instrumentation::<%= @class_name %>::Prepend
else
chain_instrument NewRelic::Agent::Instrumentation::<%= @class_name %>::Chain
end
Expand Down
24 changes: 24 additions & 0 deletions test/multiverse/suites/opensearch/Envfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# This file is distributed under New Relic's license terms.
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
# frozen_string_literal: true

suite_condition('Skip OpenSearch on GitHub Actions, service not currently available') do
ENV['CI'] != 'true'
end

instrumentation_methods :chain, :prepend

OPENSEARCH_VERSIONS = [
[nil, 2.5],
['3.4.0', 2.5],
['2.1.0', 2.4]
]

def gem_list(opensearch_version = nil)
<<~RB
gem 'opensearch-ruby'#{opensearch_version}
RB
end

create_gemfiles(OPENSEARCH_VERSIONS)

19 changes: 19 additions & 0 deletions test/multiverse/suites/opensearch/config/newrelic.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
development:
error_collector:
enabled: true
apdex_t: 0.5
monitor_mode: true
license_key: bootstrap_newrelic_admin_license_key_000
instrumentation:
opensearch: <%= $instrumentation_method %>
app_name: test
log_level: debug
host: 127.0.0.1
api_host: 127.0.0.1
transaction_trace:
record_sql: obfuscated
enabled: true
stack_trace_threshold: 0.5
transaction_threshold: 1.0
capture_params: false
Loading
Loading