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.
Files changed (77) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +28 -1
  3. data/lib/new_relic/agent.rb +1 -2
  4. data/lib/new_relic/agent/agent.rb +28 -10
  5. data/lib/new_relic/agent/agent_logger.rb +4 -3
  6. data/lib/new_relic/agent/audit_logger.rb +5 -8
  7. data/lib/new_relic/agent/configuration/default_source.rb +24 -0
  8. data/lib/new_relic/agent/cross_app_tracing.rb +21 -15
  9. data/lib/new_relic/agent/datastores/mongo.rb +25 -0
  10. data/lib/new_relic/agent/datastores/mongo/metric_generator.rb +25 -0
  11. data/lib/new_relic/agent/datastores/mongo/metric_translator.rb +189 -0
  12. data/lib/new_relic/agent/datastores/mongo/obfuscator.rb +39 -0
  13. data/lib/new_relic/agent/datastores/mongo/statement_formatter.rb +52 -0
  14. data/lib/new_relic/agent/harvester.rb +55 -0
  15. data/lib/new_relic/agent/instrumentation/mongo.rb +139 -0
  16. data/lib/new_relic/agent/instrumentation/net.rb +6 -11
  17. data/lib/new_relic/agent/supported_versions.rb +9 -5
  18. data/lib/new_relic/agent/transaction_sampler.rb +4 -0
  19. data/lib/new_relic/version.rb +1 -1
  20. data/lib/tasks/versions.rake +1 -1
  21. data/test/agent_helper.rb +4 -0
  22. data/test/environments/norails/Gemfile +3 -0
  23. data/test/environments/rails40/Gemfile +5 -1
  24. data/test/flaky_proxy/Gemfile +3 -0
  25. data/test/flaky_proxy/README.md +82 -0
  26. data/test/flaky_proxy/lib/flaky_proxy.rb +22 -0
  27. data/test/flaky_proxy/lib/flaky_proxy/connection.rb +45 -0
  28. data/test/flaky_proxy/lib/flaky_proxy/http_message.rb +105 -0
  29. data/test/flaky_proxy/lib/flaky_proxy/proxy.rb +42 -0
  30. data/test/flaky_proxy/lib/flaky_proxy/rule.rb +75 -0
  31. data/test/flaky_proxy/lib/flaky_proxy/rule_set.rb +37 -0
  32. data/test/flaky_proxy/lib/flaky_proxy/server.rb +22 -0
  33. data/test/flaky_proxy/script/flaky_proxy +39 -0
  34. data/test/helpers/exceptions.rb +16 -0
  35. data/test/helpers/mongo_metric_builder.rb +29 -0
  36. data/test/multiverse/lib/multiverse/suite.rb +1 -0
  37. data/test/multiverse/suites/curb/curb_test.rb +0 -1
  38. data/test/multiverse/suites/deferred_instrumentation/sinatra_test.rb +4 -3
  39. data/test/multiverse/suites/excon/excon_test.rb +0 -1
  40. data/test/multiverse/suites/httpclient/httpclient_test.rb +0 -1
  41. data/test/multiverse/suites/mongo/Envfile +66 -0
  42. data/test/multiverse/suites/mongo/config/newrelic.yml +19 -0
  43. data/test/multiverse/suites/mongo/mongo_instrumentation_test.rb +418 -0
  44. data/test/multiverse/suites/mongo/mongo_unsupported_version_test.rb +36 -0
  45. data/test/multiverse/suites/net_http/net_http_test.rb +2 -4
  46. data/test/multiverse/suites/rails/Envfile +4 -4
  47. data/test/multiverse/suites/rails/config/newrelic.yml +1 -1
  48. data/test/multiverse/suites/rails/error_tracing_test.rb +7 -7
  49. data/test/multiverse/suites/sidekiq/Envfile +1 -1
  50. data/test/multiverse/suites/sidekiq/sidekiq_instrumentation_test.rb +0 -1
  51. data/test/multiverse/suites/sinatra/sinatra_classic_test.rb +5 -3
  52. data/test/multiverse/suites/sinatra/sinatra_modular_test.rb +5 -3
  53. data/test/multiverse/suites/typhoeus/typhoeus_test.rb +0 -1
  54. data/test/new_relic/agent/agent_logger_test.rb +9 -1
  55. data/test/new_relic/agent/agent_test.rb +66 -1
  56. data/test/new_relic/agent/agent_test_controller.rb +1 -2
  57. data/test/new_relic/agent/audit_logger_test.rb +12 -4
  58. data/test/new_relic/agent/configuration/orphan_configuration_test.rb +11 -2
  59. data/test/new_relic/agent/cpu_sampler_test.rb +1 -0
  60. data/test/new_relic/agent/cross_app_tracing_test.rb +60 -0
  61. data/test/new_relic/agent/datastores/mongo/metric_generator_test.rb +43 -0
  62. data/test/new_relic/agent/datastores/mongo/metric_translator_test.rb +301 -0
  63. data/test/new_relic/agent/datastores/mongo/obfuscator_test.rb +91 -0
  64. data/test/new_relic/agent/datastores/mongo/statement_formatter_test.rb +71 -0
  65. data/test/new_relic/agent/harvester_test.rb +85 -0
  66. data/test/new_relic/agent/transaction_sampler_test.rb +5 -0
  67. data/test/new_relic/agent/worker_loop_test.rb +3 -5
  68. data/test/new_relic/http_client_test_cases.rb +65 -81
  69. data/test/new_relic/noticed_error_test.rb +14 -16
  70. data/test/performance/lib/performance.rb +1 -0
  71. data/test/performance/lib/performance/console_reporter.rb +6 -2
  72. data/test/performance/lib/performance/instrumentor.rb +1 -15
  73. data/test/performance/lib/performance/platform.rb +35 -0
  74. data/test/performance/lib/performance/test_case.rb +16 -1
  75. data/test/performance/suites/marshalling.rb +73 -0
  76. metadata +48 -19
  77. 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
 
@@ -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 run_loop_before_exit
228
+ @worker_loop.run_task if Agent.config[:force_send]
207
229
  @worker_loop.stop
208
230
  end
231
+ end
209
232
 
210
- ::NewRelic::Agent.logger.info "Starting Agent shutdown"
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
- def @log.format_message(severity, timestamp, progname, msg)
147
- prefix = @logdev.dev == STDOUT ? '** [NewRelic]' : ''
148
- prefix + "[#{timestamp.strftime("%m/%d/%y %H:%M:%S %z")} #{Socket.gethostname} (#{$$})] #{severity} : #{msg}\n"
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 = 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 log_formatter
69
- if @formatter.nil?
70
- @formatter = Logger::Formatter.new
71
- def @formatter.call(severity, time, progname, msg)
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 ) if t0
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 used for this request
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
- segment = stats_engine.push_scope( :net_http, t0 )
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
- # Add TT custom parameters
102
- segment.name = scoped_metric
103
- add_transaction_trace_parameters(request, response)
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
- # We always need to pop the scope stack to avoid an inconsistent
107
- # state, which will prevent tracing of the whole transaction.
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
- # Memoized fetcher for the cross app encoding key. Raises a
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