newrelic_rpm 3.7.0.177 → 3.7.1.180
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +28 -1
- data/lib/new_relic/agent.rb +1 -2
- data/lib/new_relic/agent/agent.rb +28 -10
- data/lib/new_relic/agent/agent_logger.rb +4 -3
- data/lib/new_relic/agent/audit_logger.rb +5 -8
- data/lib/new_relic/agent/configuration/default_source.rb +24 -0
- data/lib/new_relic/agent/cross_app_tracing.rb +21 -15
- data/lib/new_relic/agent/datastores/mongo.rb +25 -0
- data/lib/new_relic/agent/datastores/mongo/metric_generator.rb +25 -0
- data/lib/new_relic/agent/datastores/mongo/metric_translator.rb +189 -0
- data/lib/new_relic/agent/datastores/mongo/obfuscator.rb +39 -0
- data/lib/new_relic/agent/datastores/mongo/statement_formatter.rb +52 -0
- data/lib/new_relic/agent/harvester.rb +55 -0
- data/lib/new_relic/agent/instrumentation/mongo.rb +139 -0
- data/lib/new_relic/agent/instrumentation/net.rb +6 -11
- data/lib/new_relic/agent/supported_versions.rb +9 -5
- data/lib/new_relic/agent/transaction_sampler.rb +4 -0
- data/lib/new_relic/version.rb +1 -1
- data/lib/tasks/versions.rake +1 -1
- data/test/agent_helper.rb +4 -0
- data/test/environments/norails/Gemfile +3 -0
- data/test/environments/rails40/Gemfile +5 -1
- data/test/flaky_proxy/Gemfile +3 -0
- data/test/flaky_proxy/README.md +82 -0
- data/test/flaky_proxy/lib/flaky_proxy.rb +22 -0
- data/test/flaky_proxy/lib/flaky_proxy/connection.rb +45 -0
- data/test/flaky_proxy/lib/flaky_proxy/http_message.rb +105 -0
- data/test/flaky_proxy/lib/flaky_proxy/proxy.rb +42 -0
- data/test/flaky_proxy/lib/flaky_proxy/rule.rb +75 -0
- data/test/flaky_proxy/lib/flaky_proxy/rule_set.rb +37 -0
- data/test/flaky_proxy/lib/flaky_proxy/server.rb +22 -0
- data/test/flaky_proxy/script/flaky_proxy +39 -0
- data/test/helpers/exceptions.rb +16 -0
- data/test/helpers/mongo_metric_builder.rb +29 -0
- data/test/multiverse/lib/multiverse/suite.rb +1 -0
- data/test/multiverse/suites/curb/curb_test.rb +0 -1
- data/test/multiverse/suites/deferred_instrumentation/sinatra_test.rb +4 -3
- data/test/multiverse/suites/excon/excon_test.rb +0 -1
- data/test/multiverse/suites/httpclient/httpclient_test.rb +0 -1
- data/test/multiverse/suites/mongo/Envfile +66 -0
- data/test/multiverse/suites/mongo/config/newrelic.yml +19 -0
- data/test/multiverse/suites/mongo/mongo_instrumentation_test.rb +418 -0
- data/test/multiverse/suites/mongo/mongo_unsupported_version_test.rb +36 -0
- data/test/multiverse/suites/net_http/net_http_test.rb +2 -4
- data/test/multiverse/suites/rails/Envfile +4 -4
- data/test/multiverse/suites/rails/config/newrelic.yml +1 -1
- data/test/multiverse/suites/rails/error_tracing_test.rb +7 -7
- data/test/multiverse/suites/sidekiq/Envfile +1 -1
- data/test/multiverse/suites/sidekiq/sidekiq_instrumentation_test.rb +0 -1
- data/test/multiverse/suites/sinatra/sinatra_classic_test.rb +5 -3
- data/test/multiverse/suites/sinatra/sinatra_modular_test.rb +5 -3
- data/test/multiverse/suites/typhoeus/typhoeus_test.rb +0 -1
- data/test/new_relic/agent/agent_logger_test.rb +9 -1
- data/test/new_relic/agent/agent_test.rb +66 -1
- data/test/new_relic/agent/agent_test_controller.rb +1 -2
- data/test/new_relic/agent/audit_logger_test.rb +12 -4
- data/test/new_relic/agent/configuration/orphan_configuration_test.rb +11 -2
- data/test/new_relic/agent/cpu_sampler_test.rb +1 -0
- data/test/new_relic/agent/cross_app_tracing_test.rb +60 -0
- data/test/new_relic/agent/datastores/mongo/metric_generator_test.rb +43 -0
- data/test/new_relic/agent/datastores/mongo/metric_translator_test.rb +301 -0
- data/test/new_relic/agent/datastores/mongo/obfuscator_test.rb +91 -0
- data/test/new_relic/agent/datastores/mongo/statement_formatter_test.rb +71 -0
- data/test/new_relic/agent/harvester_test.rb +85 -0
- data/test/new_relic/agent/transaction_sampler_test.rb +5 -0
- data/test/new_relic/agent/worker_loop_test.rb +3 -5
- data/test/new_relic/http_client_test_cases.rb +65 -81
- data/test/new_relic/noticed_error_test.rb +14 -16
- data/test/performance/lib/performance.rb +1 -0
- data/test/performance/lib/performance/console_reporter.rb +6 -2
- data/test/performance/lib/performance/instrumentor.rb +1 -15
- data/test/performance/lib/performance/platform.rb +35 -0
- data/test/performance/lib/performance/test_case.rb +16 -1
- data/test/performance/suites/marshalling.rb +73 -0
- metadata +48 -19
- metadata.gz.sig +1 -2
data.tar.gz.sig
CHANGED
Binary file
|
data/CHANGELOG
CHANGED
@@ -1,10 +1,37 @@
|
|
1
1
|
# New Relic Ruby Agent Release Notes #
|
2
2
|
|
3
|
+
## v3.7.1 ##
|
4
|
+
|
5
|
+
* MongoDB support
|
6
|
+
|
7
|
+
The Ruby agent provides support for the mongo gem, versions 1.8 and 1.9!
|
8
|
+
Mongo calls are captured for transaction traces along with their parameters,
|
9
|
+
and time spent in Mongo shows up on the Database tab.
|
10
|
+
|
11
|
+
Support for more Mongo gems and more UI goodness will be coming, so watch
|
12
|
+
http://docs.newrelic.com/docs/ruby/mongo for up-to-date status.
|
13
|
+
|
14
|
+
* Harvest thread restarts for forked and daemonized processes
|
15
|
+
|
16
|
+
Historically framework specific code was necessary for the Ruby agent to
|
17
|
+
successfully report data after an app forked or daemonized. Gems or scripts
|
18
|
+
with daemonizing modes had to wait for agent support or find workarounds.
|
19
|
+
|
20
|
+
With 3.7.1 setting `restart_thread_in_child: true` in your newrelic.yml
|
21
|
+
automatically restarts the agent in child processes without requiring custom
|
22
|
+
code. For now the feature is opt-in, but future releases may default it on.
|
23
|
+
|
24
|
+
* Fix for missing HTTP time
|
25
|
+
|
26
|
+
The agent previously did not include connection establishment time for
|
27
|
+
outgoing Net::HTTP requests. This has been corrected, and reported HTTP
|
28
|
+
timings should now be more accurate.
|
29
|
+
|
3
30
|
## v3.7.0 ##
|
4
31
|
|
5
32
|
* Official Rubinius support (for Rubinius >= 2.2.1)
|
6
33
|
|
7
|
-
We're happy to say that all known issues with the Ruby agent running on
|
34
|
+
We're happy to say that all known issues with the Ruby agent running on
|
8
35
|
Rubinius have been resolved as of Rubinius version 2.2.1! See
|
9
36
|
http://docs.newrelic.com/docs/ruby/rubinius for the most up-to-date status.
|
10
37
|
|
data/lib/new_relic/agent.rb
CHANGED
@@ -391,8 +391,7 @@ module NewRelic
|
|
391
391
|
# Yield to the block without collecting any metrics or traces in
|
392
392
|
# any of the subsequent calls. If executed recursively, will keep
|
393
393
|
# track of the first entry point and turn on tracing again after
|
394
|
-
# leaving that block. This uses the thread local
|
395
|
-
# +newrelic_untrace+
|
394
|
+
# leaving that block. This uses the thread local TransactionState.
|
396
395
|
#
|
397
396
|
# @api public
|
398
397
|
#
|
@@ -10,6 +10,7 @@ require 'zlib'
|
|
10
10
|
require 'stringio'
|
11
11
|
require 'new_relic/agent/sampled_buffer'
|
12
12
|
require 'new_relic/agent/autostart'
|
13
|
+
require 'new_relic/agent/harvester'
|
13
14
|
require 'new_relic/agent/new_relic_service'
|
14
15
|
require 'new_relic/agent/pipe_service'
|
15
16
|
require 'new_relic/agent/configuration/manager'
|
@@ -50,6 +51,7 @@ module NewRelic
|
|
50
51
|
@request_sampler = NewRelic::Agent::RequestSampler.new(@events)
|
51
52
|
@harvest_samplers = NewRelic::Agent::SamplerCollection.new(@events)
|
52
53
|
@javascript_instrumentor = NewRelic::Agent::JavascriptInstrumentor.new(@events)
|
54
|
+
@harvester = NewRelic::Agent::Harvester.new(@events)
|
53
55
|
|
54
56
|
@connect_state = :pending
|
55
57
|
@connect_attempts = 0
|
@@ -160,6 +162,8 @@ module NewRelic
|
|
160
162
|
# connection, this tells me to only try it once so this method returns
|
161
163
|
# quickly if there is some kind of latency with the server.
|
162
164
|
def after_fork(options={})
|
165
|
+
@harvester.mark_started
|
166
|
+
|
163
167
|
Agent.config.apply_config(NewRelic::Agent::Configuration::ManualSource.new(options), 1)
|
164
168
|
|
165
169
|
if channel_id = options[:report_to_channel]
|
@@ -200,22 +204,42 @@ module NewRelic
|
|
200
204
|
# Options:
|
201
205
|
# :force_send => (true/false) # force the agent to send data
|
202
206
|
def shutdown(options={})
|
203
|
-
run_loop_before_exit = Agent.config[:force_send]
|
204
207
|
return if not started?
|
208
|
+
::NewRelic::Agent.logger.info "Starting Agent shutdown"
|
209
|
+
|
210
|
+
stop_worker_loop
|
211
|
+
trap_signals_for_litespeed
|
212
|
+
untraced_graceful_disconnect
|
213
|
+
revert_to_default_configuration
|
214
|
+
|
215
|
+
@started = nil
|
216
|
+
Control.reset
|
217
|
+
end
|
218
|
+
|
219
|
+
def revert_to_default_configuration
|
220
|
+
NewRelic::Agent.config.remove_config do |config|
|
221
|
+
config.class == NewRelic::Agent::Configuration::ManualSource ||
|
222
|
+
config.class == NewRelic::Agent::Configuration::ServerSource
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def stop_worker_loop
|
205
227
|
if @worker_loop
|
206
|
-
@worker_loop.run_task if
|
228
|
+
@worker_loop.run_task if Agent.config[:force_send]
|
207
229
|
@worker_loop.stop
|
208
230
|
end
|
231
|
+
end
|
209
232
|
|
210
|
-
|
211
|
-
|
233
|
+
def trap_signals_for_litespeed
|
212
234
|
# if litespeed, then ignore all future SIGUSR1 - it's
|
213
235
|
# litespeed trying to shut us down
|
214
236
|
if Agent.config[:dispatcher] == :litespeed
|
215
237
|
Signal.trap("SIGUSR1", "IGNORE")
|
216
238
|
Signal.trap("SIGTERM", "IGNORE")
|
217
239
|
end
|
240
|
+
end
|
218
241
|
|
242
|
+
def untraced_graceful_disconnect
|
219
243
|
begin
|
220
244
|
NewRelic::Agent.disable_all_tracing do
|
221
245
|
graceful_disconnect
|
@@ -223,12 +247,6 @@ module NewRelic
|
|
223
247
|
rescue => e
|
224
248
|
::NewRelic::Agent.logger.error e
|
225
249
|
end
|
226
|
-
NewRelic::Agent.config.remove_config do |config|
|
227
|
-
config.class == NewRelic::Agent::Configuration::ManualSource ||
|
228
|
-
config.class == NewRelic::Agent::Configuration::ServerSource
|
229
|
-
end
|
230
|
-
@started = nil
|
231
|
-
Control.reset
|
232
250
|
end
|
233
251
|
|
234
252
|
# Tells the statistics engine we are starting a new transaction
|
@@ -143,9 +143,10 @@ module NewRelic
|
|
143
143
|
end
|
144
144
|
|
145
145
|
def set_log_format!
|
146
|
-
|
147
|
-
|
148
|
-
|
146
|
+
@hostname = Socket.gethostname
|
147
|
+
@prefix = wants_stdout? ? '** [NewRelic]' : ''
|
148
|
+
@log.formatter = Proc.new do |severity, timestamp, progname, msg|
|
149
|
+
"#{@prefix}[#{timestamp.strftime("%m/%d/%y %H:%M:%S %z")} #{@hostname} (#{$$})] #{severity} : #{msg}\n"
|
149
150
|
end
|
150
151
|
end
|
151
152
|
|
@@ -42,7 +42,7 @@ module NewRelic
|
|
42
42
|
path = ensure_log_path
|
43
43
|
if path
|
44
44
|
@log = ::Logger.new(path)
|
45
|
-
@log.formatter =
|
45
|
+
@log.formatter = create_log_formatter
|
46
46
|
::NewRelic::Agent.logger.info("Audit log enabled at '#{path}'")
|
47
47
|
else
|
48
48
|
@log = NewRelic::Agent::NullLogger.new
|
@@ -65,14 +65,11 @@ module NewRelic
|
|
65
65
|
path
|
66
66
|
end
|
67
67
|
|
68
|
-
def
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
"[#{time} #{Socket.gethostname} (#{$$})] : #{msg}\n"
|
73
|
-
end
|
68
|
+
def create_log_formatter
|
69
|
+
@hostname = Socket.gethostname
|
70
|
+
Proc.new do |severity, time, progname, msg|
|
71
|
+
"[#{time} #{@hostname} (#{$$})] : #{msg}\n"
|
74
72
|
end
|
75
|
-
@formatter
|
76
73
|
end
|
77
74
|
end
|
78
75
|
end
|
@@ -630,6 +630,12 @@ module NewRelic
|
|
630
630
|
:type => Boolean,
|
631
631
|
:description => 'Enable or disable sequel instrumentation.'
|
632
632
|
},
|
633
|
+
:disable_mongo => {
|
634
|
+
:default => false,
|
635
|
+
:public => true,
|
636
|
+
:type => Boolean,
|
637
|
+
:description => 'Enable or disable MongoDB instrumentation.'
|
638
|
+
},
|
633
639
|
:'slow_sql.enabled' => {
|
634
640
|
:default => DefaultSource.slow_sql_enabled,
|
635
641
|
:public => true,
|
@@ -654,6 +660,18 @@ module NewRelic
|
|
654
660
|
:type => String,
|
655
661
|
:description => "Obfuscation level for slow sql queries (e.g. 'obfuscated', 'raw', 'none')."
|
656
662
|
},
|
663
|
+
:'mongo.capture_queries' => {
|
664
|
+
:default => true,
|
665
|
+
:public => true,
|
666
|
+
:type => Boolean,
|
667
|
+
:description => "Enable or disable capturing Mongo queries in transaction traces."
|
668
|
+
},
|
669
|
+
:'mongo.obfuscate_queries' => {
|
670
|
+
:default => true,
|
671
|
+
:public => true,
|
672
|
+
:type => Boolean,
|
673
|
+
:description => "Enable or disable obfuscation of Mongo queries in transaction traces."
|
674
|
+
},
|
657
675
|
:'error_collector.enabled' => {
|
658
676
|
:default => true,
|
659
677
|
:public => true,
|
@@ -854,6 +872,12 @@ module NewRelic
|
|
854
872
|
:type => Boolean,
|
855
873
|
:description => 'Include TT custom params in real user monitoring script in outgoing responses.'
|
856
874
|
},
|
875
|
+
:restart_thread_in_children => {
|
876
|
+
:default => false,
|
877
|
+
:public => false,
|
878
|
+
:type => Boolean,
|
879
|
+
:description => 'Controls whether to check on running a transaction whether to respawn the harvest thread.'
|
880
|
+
},
|
857
881
|
}.freeze
|
858
882
|
|
859
883
|
end
|
@@ -36,11 +36,11 @@ module NewRelic
|
|
36
36
|
def trace_http_request( request )
|
37
37
|
return yield unless NewRelic::Agent.is_execution_traced?
|
38
38
|
|
39
|
-
t0, segment = start_trace( request )
|
40
39
|
begin
|
40
|
+
t0, segment = start_trace( request )
|
41
41
|
response = yield
|
42
42
|
ensure
|
43
|
-
finish_trace( t0, segment, request, response )
|
43
|
+
finish_trace( t0, segment, request, response )
|
44
44
|
end
|
45
45
|
|
46
46
|
return response
|
@@ -55,21 +55,24 @@ module NewRelic
|
|
55
55
|
# to make the request (e.g. 'Net::HTTP' or 'Typhoeus')
|
56
56
|
# * host - Return a String with the hostname or IP of the host being
|
57
57
|
# communicated with.
|
58
|
-
# * method - Return a String with the HTTP method name
|
58
|
+
# * method - Return a String with the HTTP method name for this request
|
59
59
|
# * [](key) - Lookup an HTTP request header by name
|
60
60
|
# * []=(key, val) - Set an HTTP request header by name
|
61
61
|
# * uri - Full URI of the request
|
62
|
+
#
|
63
|
+
# This method MUST return a pair. The first item always returns the
|
64
|
+
# starting time of the trace, even if an error occurs. The second item is
|
65
|
+
# the transaction segment if it was sucessfully pushed.
|
62
66
|
def start_trace( request )
|
63
|
-
inject_request_headers( request ) if cross_app_enabled?
|
64
|
-
|
65
|
-
# Create a segment and time the call
|
66
67
|
t0 = Time.now
|
67
|
-
|
68
|
+
|
69
|
+
inject_request_headers( request ) if cross_app_enabled?
|
70
|
+
segment = stats_engine.push_scope( :http_request, t0 )
|
68
71
|
|
69
72
|
return t0, segment
|
70
73
|
rescue => err
|
71
74
|
NewRelic::Agent.logger.error "Uncaught exception while tracing HTTP request", err
|
72
|
-
return nil
|
75
|
+
return t0, nil
|
73
76
|
end
|
74
77
|
|
75
78
|
|
@@ -98,14 +101,17 @@ module NewRelic
|
|
98
101
|
stats_engine.record_metrics(metrics, duration)
|
99
102
|
stats_engine.record_metrics(scoped_metric, duration, :scoped => true)
|
100
103
|
|
101
|
-
#
|
102
|
-
segment
|
103
|
-
|
104
|
+
# If we don't have segment, something failed during start_trace so
|
105
|
+
# the current segment isn't the HTTP call it should have been.
|
106
|
+
if segment
|
107
|
+
segment.name = scoped_metric
|
108
|
+
add_transaction_trace_parameters(request, response)
|
109
|
+
end
|
104
110
|
end
|
105
111
|
ensure
|
106
|
-
#
|
107
|
-
# state, which
|
108
|
-
stats_engine.pop_scope( segment, scoped_metric, t1 )
|
112
|
+
# If we have a segment, always pop the scope stack to avoid an
|
113
|
+
# inconsistent state, which prevents tracing of whole transaction.
|
114
|
+
stats_engine.pop_scope( segment, scoped_metric, t1 ) if segment
|
109
115
|
end
|
110
116
|
rescue NewRelic::Agent::CrossAppTracing::Error => err
|
111
117
|
NewRelic::Agent.logger.debug "while cross app tracing", err
|
@@ -132,7 +138,7 @@ module NewRelic
|
|
132
138
|
NewRelic::Agent.config[:"cross_application_tracer.enabled"] || NewRelic::Agent.config[:cross_application_tracing]
|
133
139
|
end
|
134
140
|
|
135
|
-
#
|
141
|
+
# Fetcher for the cross app encoding key. Raises a
|
136
142
|
# NewRelic::Agent::CrossAppTracing::Error if the key isn't configured.
|
137
143
|
def cross_app_encoding_key
|
138
144
|
NewRelic::Agent.config[:encoding_key] or
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
|
+
|
5
|
+
module NewRelic
|
6
|
+
module Agent
|
7
|
+
module Datastores
|
8
|
+
module Mongo
|
9
|
+
|
10
|
+
def self.is_supported_version?
|
11
|
+
# No version constant in < 2.0 versions of Mongo :(
|
12
|
+
defined?(::Mongo) &&
|
13
|
+
defined?(::Mongo::MongoClient) &&
|
14
|
+
!is_version2
|
15
|
+
end
|
16
|
+
|
17
|
+
# At present we explicitly don't support version 2.x of the driver yet
|
18
|
+
def self.is_version2
|
19
|
+
defined?(::Mongo::VERSION) &&
|
20
|
+
NewRelic::VersionNumber.new(::Mongo::VERSION) > NewRelic::VersionNumber.new("2.0.0")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
|
+
|
5
|
+
require 'new_relic/agent/datastores/mongo/metric_translator'
|
6
|
+
|
7
|
+
module NewRelic
|
8
|
+
module Agent
|
9
|
+
module Datastores
|
10
|
+
module Mongo
|
11
|
+
module MetricGenerator
|
12
|
+
def self.generate_metrics_for(name, payload)
|
13
|
+
if NewRelic::Agent::Transaction.recording_web_transaction?
|
14
|
+
request_type = :web
|
15
|
+
else
|
16
|
+
request_type = :other
|
17
|
+
end
|
18
|
+
|
19
|
+
NewRelic::Agent::Datastores::Mongo::MetricTranslator.metrics_for(name, payload, request_type)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
|
+
|
5
|
+
require 'new_relic/agent/datastores/mongo/obfuscator'
|
6
|
+
|
7
|
+
module NewRelic
|
8
|
+
module Agent
|
9
|
+
module Datastores
|
10
|
+
module Mongo
|
11
|
+
module MetricTranslator
|
12
|
+
def self.metrics_for(name, payload, request_type = :web)
|
13
|
+
payload = {} if payload.nil?
|
14
|
+
|
15
|
+
collection = payload[:collection]
|
16
|
+
|
17
|
+
if collection_in_selector?(collection, payload)
|
18
|
+
command_key = command_key_from_selector(payload)
|
19
|
+
|
20
|
+
name = get_name_from_selector(command_key)
|
21
|
+
collection = get_collection_from_selector(command_key, payload)
|
22
|
+
log_if_unknown_command(command_key, payload)
|
23
|
+
end
|
24
|
+
|
25
|
+
if self.find_one?(name, payload)
|
26
|
+
name = 'findOne'
|
27
|
+
elsif self.find_and_remove?(name, payload)
|
28
|
+
name = 'findAndRemove'
|
29
|
+
elsif self.find_and_modify?(name, payload)
|
30
|
+
name = 'findAndModify'
|
31
|
+
elsif self.create_index?(name, payload)
|
32
|
+
name = 'createIndex'
|
33
|
+
collection = self.collection_name_from_index(payload)
|
34
|
+
elsif self.drop_indexes?(name, payload)
|
35
|
+
name = 'dropIndexes'
|
36
|
+
elsif self.drop_index?(name, payload)
|
37
|
+
name = 'dropIndex'
|
38
|
+
elsif self.re_index?(name, payload)
|
39
|
+
name = 'reIndex'
|
40
|
+
elsif self.group?(name, payload)
|
41
|
+
name = 'group'
|
42
|
+
collection = collection_name_from_group_selector(payload)
|
43
|
+
elsif self.rename_collection?(name, payload)
|
44
|
+
name = 'renameCollection'
|
45
|
+
collection = collection_name_from_rename_selector(payload)
|
46
|
+
elsif self.ismaster?(name, payload)
|
47
|
+
name = 'ismaster'
|
48
|
+
collection = collection_name_from_ismaster_selector(payload)
|
49
|
+
end
|
50
|
+
|
51
|
+
build_metrics(name, collection, request_type)
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.build_metrics(name, collection, request_type = :web)
|
55
|
+
default_metrics = [
|
56
|
+
"Datastore/statement/MongoDB/#{collection}/#{name}",
|
57
|
+
"Datastore/operation/MongoDB/#{name}",
|
58
|
+
'ActiveRecord/all'
|
59
|
+
]
|
60
|
+
|
61
|
+
if request_type == :web
|
62
|
+
default_metrics << 'Datastore/allWeb'
|
63
|
+
else
|
64
|
+
default_metrics << 'Datastore/allOther'
|
65
|
+
end
|
66
|
+
|
67
|
+
default_metrics
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.collection_in_selector?(collection, payload)
|
71
|
+
collection == '$cmd' && payload[:selector]
|
72
|
+
end
|
73
|
+
|
74
|
+
NAMES_IN_SELECTOR = [
|
75
|
+
:findandmodify,
|
76
|
+
|
77
|
+
"aggregate",
|
78
|
+
"count",
|
79
|
+
"group",
|
80
|
+
"mapreduce",
|
81
|
+
|
82
|
+
:distinct,
|
83
|
+
|
84
|
+
:deleteIndexes,
|
85
|
+
:reIndex,
|
86
|
+
|
87
|
+
:ismaster,
|
88
|
+
:collstats,
|
89
|
+
:renameCollection,
|
90
|
+
:drop,
|
91
|
+
]
|
92
|
+
|
93
|
+
UNKNOWN_COMMAND = "UnknownCommand"
|
94
|
+
UNKNOWN_COLLECTION = "UnknownCollection"
|
95
|
+
|
96
|
+
def self.command_key_from_selector(payload)
|
97
|
+
selector = payload[:selector]
|
98
|
+
NAMES_IN_SELECTOR.find do |check_name|
|
99
|
+
selector.key?(check_name)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.get_name_from_selector(command_key)
|
104
|
+
return UNKNOWN_COMMAND unless command_key
|
105
|
+
|
106
|
+
command_key.to_sym
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.get_collection_from_selector(command_key, payload)
|
110
|
+
return UNKNOWN_COLLECTION unless command_key
|
111
|
+
|
112
|
+
payload[:selector][command_key]
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.log_if_unknown_command(command_key, payload)
|
116
|
+
unless command_key
|
117
|
+
NewRelic::Agent.logger.debug("Unknown Mongo command: #{Obfuscator.obfuscate_statement(payload).inspect}")
|
118
|
+
NewRelic::Agent.increment_metric("Supportability/Mongo/UnknownCommand")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.find_one?(name, payload)
|
123
|
+
name == :find && payload[:limit] == -1
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.find_and_modify?(name, payload)
|
127
|
+
name == :findandmodify
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.find_and_remove?(name, payload)
|
131
|
+
name == :findandmodify && payload[:selector] && payload[:selector][:remove]
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.create_index?(name, payload)
|
135
|
+
name == :insert && payload[:collection] == "system.indexes"
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.drop_indexes?(name, payload)
|
139
|
+
name == :deleteIndexes && payload[:selector] && payload[:selector][:index] == "*"
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.drop_index?(name, payload)
|
143
|
+
name == :deleteIndexes
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.re_index?(name, payload)
|
147
|
+
name == :reIndex && payload[:selector] && payload[:selector][:reIndex]
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.group?(name, payload)
|
151
|
+
name == :group
|
152
|
+
end
|
153
|
+
|
154
|
+
def self.rename_collection?(name, payload)
|
155
|
+
name == :renameCollection
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.ismaster?(name, payload)
|
159
|
+
name == :ismaster
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.collection_name_from_index(payload)
|
163
|
+
if payload[:documents] && payload[:documents].first[:ns]
|
164
|
+
payload[:documents].first[:ns].split('.').last
|
165
|
+
else
|
166
|
+
'system.indexes'
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.collection_name_from_group_selector(payload)
|
171
|
+
payload[:selector]["group"]["ns"]
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.collection_name_from_rename_selector(payload)
|
175
|
+
parts = payload[:selector][:renameCollection].split('.')
|
176
|
+
parts.shift
|
177
|
+
parts.join('.')
|
178
|
+
end
|
179
|
+
|
180
|
+
def self.collection_name_from_ismaster_selector(payload)
|
181
|
+
payload[:selector][:ismaster]
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|