newrelic_rpm 3.10.0.279 → 3.11.0.283

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +61 -0
  3. data/lib/new_relic/agent.rb +14 -8
  4. data/lib/new_relic/agent/agent.rb +43 -28
  5. data/lib/new_relic/agent/agent_logger.rb +21 -20
  6. data/lib/new_relic/agent/configuration/default_source.rb +31 -1
  7. data/lib/new_relic/agent/database.rb +2 -1
  8. data/lib/new_relic/agent/datastores.rb +177 -0
  9. data/lib/new_relic/agent/datastores/metric_helper.rb +85 -0
  10. data/lib/new_relic/agent/datastores/mongo/metric_translator.rb +11 -20
  11. data/lib/new_relic/agent/deprecator.rb +18 -0
  12. data/lib/new_relic/agent/instrumentation/active_record.rb +20 -35
  13. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +116 -57
  14. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +11 -20
  15. data/lib/new_relic/agent/instrumentation/data_mapper.rb +104 -172
  16. data/lib/new_relic/agent/instrumentation/memcache.rb +104 -52
  17. data/lib/new_relic/agent/instrumentation/metric_frame.rb +9 -0
  18. data/lib/new_relic/agent/instrumentation/middleware_proxy.rb +15 -2
  19. data/lib/new_relic/agent/instrumentation/mongo.rb +5 -18
  20. data/lib/new_relic/agent/instrumentation/sequel_helper.rb +36 -0
  21. data/lib/new_relic/agent/new_relic_service.rb +4 -0
  22. data/lib/new_relic/agent/stats_engine/metric_stats.rb +2 -17
  23. data/lib/new_relic/agent/threading/backtrace_service.rb +28 -5
  24. data/lib/new_relic/agent/transaction.rb +63 -34
  25. data/lib/new_relic/agent/transaction_event_aggregator.rb +0 -4
  26. data/lib/new_relic/agent/transaction_sampler.rb +11 -5
  27. data/lib/new_relic/rack/error_collector.rb +0 -1
  28. data/lib/new_relic/version.rb +1 -1
  29. data/lib/sequel/extensions/newrelic_instrumentation.rb +28 -56
  30. data/lib/sequel/plugins/newrelic_instrumentation.rb +28 -45
  31. data/newrelic_rpm.gemspec +0 -7
  32. data/test/agent_helper.rb +35 -16
  33. data/test/environments/rails31/Gemfile +1 -0
  34. data/test/environments/rails32/Gemfile +1 -0
  35. data/test/helpers/mongo_metric_builder.rb +2 -3
  36. data/test/multiverse/lib/multiverse/output_collector.rb +24 -9
  37. data/test/multiverse/lib/multiverse/suite.rb +5 -0
  38. data/test/multiverse/suites/active_record/Envfile +6 -4
  39. data/test/multiverse/suites/active_record/active_record_test.rb +32 -73
  40. data/test/multiverse/suites/active_record/ar_method_aliasing.rb +0 -1
  41. data/test/multiverse/suites/activemerchant/activemerchant_test.rb +0 -3
  42. data/test/multiverse/suites/agent_only/agent_run_id_handling_test.rb +0 -1
  43. data/test/multiverse/suites/agent_only/audit_log_test.rb +0 -1
  44. data/test/multiverse/suites/agent_only/collector_exception_handling_test.rb +0 -2
  45. data/test/multiverse/suites/agent_only/cross_application_tracing_test.rb +0 -1
  46. data/test/multiverse/suites/agent_only/custom_analytics_events_test.rb +0 -2
  47. data/test/multiverse/suites/agent_only/custom_queue_time_test.rb +0 -1
  48. data/test/multiverse/suites/agent_only/encoding_handling_test.rb +0 -2
  49. data/test/multiverse/suites/agent_only/exclusive_time_test.rb +0 -2
  50. data/test/multiverse/suites/agent_only/harvest_timestamps_test.rb +0 -1
  51. data/test/multiverse/suites/agent_only/http_response_code_test.rb +0 -1
  52. data/test/multiverse/suites/agent_only/keepalive_test.rb +0 -1
  53. data/test/multiverse/suites/agent_only/key_transactions_test.rb +54 -9
  54. data/test/multiverse/suites/agent_only/labels_test.rb +0 -2
  55. data/test/multiverse/suites/agent_only/logging_test.rb +0 -1
  56. data/test/multiverse/suites/agent_only/marshaling_test.rb +0 -1
  57. data/test/multiverse/suites/agent_only/pipe_manager_test.rb +0 -2
  58. data/test/multiverse/suites/agent_only/rename_rule_test.rb +5 -7
  59. data/test/multiverse/suites/agent_only/rum_instrumentation_test.rb +0 -1
  60. data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +0 -2
  61. data/test/multiverse/suites/agent_only/ssl_test.rb +0 -2
  62. data/test/multiverse/suites/agent_only/synthetics_test.rb +0 -1
  63. data/test/multiverse/suites/agent_only/testing_app.rb +21 -0
  64. data/test/multiverse/suites/agent_only/thread_profiling_test.rb +1 -2
  65. data/test/multiverse/suites/agent_only/transaction_ignoring_test.rb +0 -2
  66. data/test/multiverse/suites/agent_only/utilization_data_collection_test.rb +0 -1
  67. data/test/multiverse/suites/agent_only/xray_sessions_test.rb +69 -34
  68. data/test/multiverse/suites/capistrano/deployment_test.rb +0 -1
  69. data/test/multiverse/suites/capistrano2/deployment_test.rb +0 -1
  70. data/test/multiverse/suites/config_file_loading/config_file_loading_test.rb +0 -2
  71. data/test/multiverse/suites/curb/curb_test.rb +0 -2
  72. data/test/multiverse/suites/datamapper/Envfile +26 -3
  73. data/test/multiverse/suites/datamapper/config/newrelic.yml +1 -0
  74. data/test/multiverse/suites/datamapper/datamapper_test.rb +271 -37
  75. data/test/multiverse/suites/deferred_instrumentation/sinatra_test.rb +0 -1
  76. data/test/multiverse/suites/delayed_job/Envfile +31 -8
  77. data/test/multiverse/suites/delayed_job/delayed_job_sampler_test.rb +0 -3
  78. data/test/multiverse/suites/delayed_job/unsupported_backend_test.rb +0 -3
  79. data/test/multiverse/suites/excon/excon_test.rb +0 -2
  80. data/test/multiverse/suites/grape/grape_test.rb +0 -3
  81. data/test/multiverse/suites/grape/grape_versioning_test.rb +0 -3
  82. data/test/multiverse/suites/grape/unsupported_version_test.rb +0 -3
  83. data/test/multiverse/suites/high_security/high_security_test.rb +0 -1
  84. data/test/multiverse/suites/httpclient/httpclient_test.rb +0 -2
  85. data/test/multiverse/suites/json/json_test.rb +0 -1
  86. data/test/multiverse/suites/marshalling/marshalling_test.rb +0 -1
  87. data/test/multiverse/suites/memcached/Envfile +52 -0
  88. data/test/multiverse/suites/memcached/dalli_test.rb +89 -0
  89. data/test/multiverse/suites/memcached/memcache_client_test.rb +25 -0
  90. data/test/multiverse/suites/memcached/memcache_test_cases.rb +302 -0
  91. data/test/multiverse/suites/memcached/memcached_test.rb +159 -0
  92. data/test/multiverse/suites/mongo/helpers/mongo_operation_tests.rb +26 -17
  93. data/test/multiverse/suites/mongo/mongo_connection_test.rb +0 -1
  94. data/test/multiverse/suites/mongo/mongo_instrumentation_test.rb +0 -1
  95. data/test/multiverse/suites/mongo/mongo_unsupported_version_test.rb +0 -1
  96. data/test/multiverse/suites/net_http/net_http_test.rb +0 -2
  97. data/test/multiverse/suites/padrino/padrino_test.rb +0 -3
  98. data/test/multiverse/suites/rack/http_response_code_test.rb +0 -1
  99. data/test/multiverse/suites/rack/nested_non_rack_app_test.rb +1 -1
  100. data/test/multiverse/suites/rack/rack_auto_instrumentation_test.rb +12 -12
  101. data/test/multiverse/suites/rack/rack_cascade_test.rb +0 -1
  102. data/test/multiverse/suites/rack/rack_env_mutation_test.rb +0 -1
  103. data/test/multiverse/suites/rack/rack_parameter_filtering_test.rb +0 -1
  104. data/test/multiverse/suites/rack/rack_unsupported_version_test.rb +0 -2
  105. data/test/multiverse/suites/rack/url_map_test.rb +3 -2
  106. data/test/multiverse/suites/rails/Envfile +3 -0
  107. data/test/multiverse/suites/rails/activejob_test.rb +0 -1
  108. data/test/multiverse/suites/rails/app.rb +0 -1
  109. data/test/multiverse/suites/rails/parameter_capture_test.rb +13 -0
  110. data/test/multiverse/suites/rails/rails3_app/app_rails3_plus.rb +5 -0
  111. data/test/multiverse/suites/rails/transaction_ignoring_test.rb +0 -2
  112. data/test/multiverse/suites/resque/instrumentation_test.rb +0 -2
  113. data/test/multiverse/suites/resque/resque_marshalling_test.rb +0 -1
  114. data/test/multiverse/suites/sequel/sequel_extension_test.rb +135 -0
  115. data/test/multiverse/suites/sequel/sequel_helpers.rb +62 -0
  116. data/test/multiverse/suites/sequel/sequel_plugin_test.rb +230 -0
  117. data/test/multiverse/suites/sidekiq/sidekiq_instrumentation_test.rb +0 -2
  118. data/test/multiverse/suites/sinatra/ignoring_test.rb +0 -2
  119. data/test/multiverse/suites/sinatra/nested_middleware_test.rb +0 -2
  120. data/test/multiverse/suites/sinatra/sinatra_classic_test.rb +0 -1
  121. data/test/multiverse/suites/sinatra/sinatra_error_tracing_test.rb +0 -2
  122. data/test/multiverse/suites/sinatra/sinatra_metric_explosion_test.rb +14 -12
  123. data/test/multiverse/suites/sinatra/sinatra_modular_test.rb +0 -1
  124. data/test/multiverse/suites/sinatra/sinatra_routes_test.rb +0 -2
  125. data/test/multiverse/suites/sinatra/sinatra_test_cases.rb +0 -2
  126. data/test/multiverse/suites/typhoeus/typhoeus_test.rb +0 -2
  127. data/test/multiverse/suites/yajl/yajl_test.rb +0 -1
  128. data/test/new_relic/agent/agent/start_test.rb +2 -2
  129. data/test/new_relic/agent/agent_logger_test.rb +6 -3
  130. data/test/new_relic/agent/datastores/metric_helper_test.rb +61 -0
  131. data/test/new_relic/agent/datastores/mongo/metric_translator_test.rb +20 -21
  132. data/test/new_relic/agent/datastores_test.rb +195 -0
  133. data/test/new_relic/agent/deprecator_test.rb +52 -0
  134. data/test/new_relic/agent/instrumentation/action_view_subscriber_test.rb +20 -26
  135. data/test/new_relic/agent/instrumentation/active_record_helper_test.rb +58 -53
  136. data/test/new_relic/agent/instrumentation/active_record_subscriber_test.rb +7 -20
  137. data/test/new_relic/agent/instrumentation/middleware_proxy_test.rb +19 -0
  138. data/test/new_relic/agent/instrumentation/sequel_helper_test.rb +36 -0
  139. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +1 -0
  140. data/test/new_relic/agent/method_tracer_test.rb +3 -4
  141. data/test/new_relic/agent/pipe_channel_manager_test.rb +1 -1
  142. data/test/new_relic/agent/threading/backtrace_service_test.rb +29 -4
  143. data/test/new_relic/agent/transaction_event_aggregator_test.rb +0 -4
  144. data/test/new_relic/agent/transaction_test.rb +100 -2
  145. data/test/new_relic/agent_test.rb +3 -3
  146. data/test/new_relic/http_client_test_cases.rb +0 -1
  147. data/test/new_relic/multiverse_helpers.rb +7 -0
  148. data/test/new_relic/transaction_ignoring_test_cases.rb +0 -2
  149. data/test/new_relic/transaction_sample_test.rb +11 -2
  150. data/test/performance/README.md +37 -17
  151. data/test/performance/lib/performance.rb +1 -0
  152. data/test/performance/lib/performance/baseline_compare_reporter.rb +11 -7
  153. data/test/performance/lib/performance/console_reporter.rb +29 -5
  154. data/test/performance/lib/performance/formatting_helpers.rb +22 -0
  155. data/test/performance/lib/performance/instrumentation/stackprof.rb +11 -1
  156. data/test/performance/lib/performance/result.rb +17 -6
  157. data/test/performance/lib/performance/runner.rb +7 -3
  158. data/test/performance/lib/performance/test_case.rb +89 -21
  159. data/test/performance/script/runner +13 -1
  160. data/test/performance/suites/active_record.rb +47 -0
  161. data/test/performance/suites/config.rb +4 -48
  162. data/test/performance/suites/marshalling.rb +20 -30
  163. data/test/performance/suites/queue_time.rb +1 -1
  164. data/test/performance/suites/rack_middleware.rb +1 -1
  165. data/test/performance/suites/rum_autoinsertion.rb +1 -1
  166. data/test/performance/suites/sql_obfuscation.rb +2 -2
  167. data/test/performance/suites/startup.rb +1 -1
  168. data/test/performance/suites/stats_hash.rb +7 -11
  169. data/test/performance/suites/thread_profiling.rb +20 -25
  170. data/test/performance/suites/trace_execution_scoped.rb +2 -2
  171. data/test/performance/suites/transaction_tracing.rb +4 -2
  172. data/test/test_helper.rb +5 -1
  173. metadata +53 -100
  174. data.tar.gz.sig +0 -0
  175. data/gem-public_cert.pem +0 -20
  176. data/lib/new_relic/agent/datastores/mongo/metric_generator.rb +0 -33
  177. data/test/multiverse/suites/sequel/sequel_instrumentation_test.rb +0 -289
  178. data/test/new_relic/agent/datastores/mongo/metric_generator_test.rb +0 -69
  179. data/test/new_relic/agent/memcache_instrumentation_test.rb +0 -155
  180. metadata.gz.sig +0 -2
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4556b4a30019cb741eba3e669f57af080c0189e3
4
+ data.tar.gz: cc3e6812a23b94c1e5ea69a6ccc442afb5c08ad7
5
+ SHA512:
6
+ metadata.gz: d758439faefa78cb3673721f575f8cdf07caadcafd124e6d61f16676a3bd76874d8a92d0817e564bf8842ab19e1e494a0a80597a0872c6cc158b8db0dc7b1212
7
+ data.tar.gz: a14aa6eb45971e5b4f9ddc45376c3ef8d0b737cfb968bd07ffe48f77855abe80a9ce0091490f8927b37c988ad4df3b861257e46684b2c815e585f77207b1cbd6
data/CHANGELOG CHANGED
@@ -1,5 +1,66 @@
1
1
  # New Relic Ruby Agent Release Notes #
2
2
 
3
+ ## v3.11.0 ##
4
+
5
+ * Unified view for SQL database and NoSQL datastore products.
6
+
7
+ The response time charts in the application overview page will now include
8
+ NoSQL datastores, such as MongoDB, and also the product name of existing SQL
9
+ databases such as MySQL, Postgres, etc.
10
+
11
+ The Databases page will now enable the filtering of metrics and operations
12
+ by product, and includes a table listing all operations.
13
+
14
+ For existing SQL databases, in addition to the existing breakdown of SQL
15
+ statements and operations, the queries are now also associated with the
16
+ database product being used.
17
+
18
+ For NoSQL datastores, such as MongoDB, we have now added information about
19
+ operations performed against those products, similar to what is being done
20
+ for SQL databases.
21
+
22
+ Because this introduces a notable change to how SQL database metrics are
23
+ collected, it is important that you upgrade the agent version on all hosts.
24
+ If you are unable to transition to the latest agent version on all hosts at
25
+ the same time, you can still access old and new metric data for SQL
26
+ databases, but the information will be split across two separate views.
27
+
28
+ For more information see https://docs.newrelic.com/docs/apm/applications-menu/monitoring/databases-slow-queries-dashboard
29
+
30
+ * Track background transactions as Key Transactions
31
+
32
+ In prior versions of the Ruby agent, only web transactions could be tracked
33
+ as Key Transactions. This functionality is now available to all
34
+ transactions, including custom Apdex values and X-Ray sessions.
35
+
36
+ For more information see https://docs.newrelic.com/docs/apm/selected-transactions/key-transactions/key-transactions-tracking-important-transactions-or-events
37
+
38
+ * More support and documentation for third-party extensions
39
+
40
+ It's always been possible to write extension gems for the Ruby agent, but
41
+ now there's one location with best practices and recommendations to guide
42
+ you in writing extensions. Check out
43
+ https://docs.newrelic.com/docs/agents/ruby-agent/frameworks/third-party-instrumentation
44
+
45
+ We've also added simpler APIs for tracing datastores and testing your
46
+ extensions. It's our way of giving back to everyone who's helped build on
47
+ the agent over the years. <3
48
+
49
+ * Fix for anonymous class middleware naming
50
+
51
+ Metric names based off anonymous middlewares lacked a class name in the UI.
52
+ The Ruby agent will now look for a superclass, or default to AnonymousClass
53
+ in those cases.
54
+
55
+ * Improved exit behavior in the presence of Sinatra
56
+
57
+ The agent uses an `at_exit` hook to ensure data from the last < 60s before a
58
+ process exits is sent to New Relic. Previously, this hook was skipped if
59
+ Sinatra::Application was defined. This unfortunately missed data for
60
+ short-lived background processes that required, but didn't run, Sinatra. Now
61
+ the agent only skips its `at_exit` hook if Sinatra actually runs from
62
+ `at_exit`.
63
+
3
64
  ## v3.10.0 ##
4
65
 
5
66
  * Support for the Grape framework
@@ -313,6 +313,14 @@ module NewRelic
313
313
  agent.drop_buffered_data
314
314
  end
315
315
 
316
+ # Require agent testing helper methods
317
+ #
318
+ # @api public
319
+ def require_test_helper
320
+ path = File.join(__FILE__, '..', '..', '..', 'test', 'agent_helper')
321
+ require File.expand_path(path)
322
+ end
323
+
316
324
  # Deprecated in favor of drop_buffered_data
317
325
  #
318
326
  # @api public
@@ -608,16 +616,14 @@ module NewRelic
608
616
  end
609
617
  end
610
618
 
611
- # Yield to a block that is run with a database metric name
612
- # context. This means the Database instrumentation will use this
613
- # for the metric name if it does not otherwise know about a model.
614
- # This is re-entrant.
619
+ # Yield to a block that is run with a database metric name context. This means
620
+ # the Database instrumentation will use this for the metric name if it does not
621
+ # otherwise know about a model. This is re-entrant.
615
622
  #
616
- # * <tt>model</tt> is the DB model class
617
- # * <tt>method</tt> is the name of the finder method or other
618
- # method to identify the operation with.
623
+ # @param [String,Class,#to_s] model the DB model class
619
624
  #
620
- # @api public
625
+ # @param [String] method the name of the finder method or other method to
626
+ # identify the operation with.
621
627
  #
622
628
  def with_database_metric_name(model, method, &block) #THREAD_LOCAL_ACCESS
623
629
  if txn = Transaction.tl_current
@@ -337,37 +337,52 @@ module NewRelic
337
337
  NewRelic::Agent.disable_all_tracing { connect(:keep_retrying => false) }
338
338
  end
339
339
 
340
- # If we're using sinatra, old versions run in an at_exit
341
- # block so we should probably know that
342
- def using_sinatra?
343
- defined?(Sinatra::Application)
344
- end
345
-
346
- # we should not set an at_exit block if people are using
347
- # these as they don't do standard at_exit behavior per MRI/YARV
348
- def weird_ruby?
349
- NewRelic::LanguageSupport.using_engine?('rbx') ||
350
- NewRelic::LanguageSupport.using_engine?('jruby') ||
351
- using_sinatra?
340
+ # This matters when the following three criteria are met:
341
+ #
342
+ # 1. A Sinatra 'classic' application is being run
343
+ # 2. The app is being run by executing the main file directly, rather
344
+ # than via a config.ru file.
345
+ # 3. newrelic_rpm is required *after* sinatra
346
+ #
347
+ # In this case, the entire application runs from an at_exit handler in
348
+ # Sinatra, and if we were to install ours, it would be executed before
349
+ # the one in Sinatra, meaning that we'd shutdown the agent too early
350
+ # and never collect any data.
351
+ def sinatra_classic_app?
352
+ (
353
+ defined?(Sinatra::Application) &&
354
+ Sinatra::Application.respond_to?(:run) &&
355
+ Sinatra::Application.run?
356
+ )
357
+ end
358
+
359
+ def should_install_exit_handler?
360
+ (
361
+ Agent.config[:send_data_on_exit] &&
362
+ !NewRelic::LanguageSupport.using_engine?('rbx') &&
363
+ !NewRelic::LanguageSupport.using_engine?('jruby') &&
364
+ !sinatra_classic_app?
365
+ )
366
+ end
367
+
368
+ # There's an MRI 1.9 bug that loses exit codes in at_exit blocks.
369
+ # A workaround is necessary to get correct exit codes for the agent's
370
+ # test suites.
371
+ # http://bugs.ruby-lang.org/issues/5218
372
+ def need_exit_code_workaround?
373
+ defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION.match(/^1\.9/)
352
374
  end
353
375
 
354
- # Installs our exit handler, which exploits the weird
355
- # behavior of at_exit blocks to make sure it runs last, by
356
- # doing an at_exit within an at_exit block.
357
376
  def install_exit_handler
358
- if Agent.config[:send_data_on_exit] && !weird_ruby?
359
- at_exit do
360
- # Workaround for MRI 1.9 bug that loses exit codes in at_exit blocks.
361
- # This is necessary to get correct exit codes for the agent's
362
- # test suites.
363
- # http://bugs.ruby-lang.org/issues/5218
364
- if defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION.match(/^1\.9/)
365
- exit_status = $!.status if $!.is_a?(SystemExit)
366
- shutdown
367
- exit exit_status if exit_status
368
- else
369
- shutdown
370
- end
377
+ return unless should_install_exit_handler?
378
+ NewRelic::Agent.logger.debug("Installing at_exit handler")
379
+ at_exit do
380
+ if need_exit_code_workaround?
381
+ exit_status = $!.status if $!.is_a?(SystemExit)
382
+ shutdown
383
+ exit exit_status if exit_status
384
+ else
385
+ shutdown
371
386
  end
372
387
  end
373
388
  end
@@ -2,6 +2,7 @@
2
2
  # This file is distributed under New Relic's license terms.
3
3
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
4
 
5
+ require 'thread'
5
6
  require 'logger'
6
7
  require 'new_relic/agent/hostname'
7
8
 
@@ -9,9 +10,8 @@ module NewRelic
9
10
  module Agent
10
11
  class AgentLogger
11
12
 
12
- attr_reader :already_logged
13
-
14
13
  def initialize(root = "", override_logger=nil)
14
+ @already_logged_lock = Mutex.new
15
15
  clear_already_logged
16
16
  create_log(root, override_logger)
17
17
  set_log_level!
@@ -43,25 +43,24 @@ module NewRelic
43
43
  NUM_LOG_ONCE_KEYS = 1000
44
44
 
45
45
  def log_once(level, key, *msgs)
46
- # Since `already_logged` might change between calls, just grab it once
47
- # and use it throughout this method.
48
- logged = already_logged
49
-
50
- return if logged.include?(key)
51
-
52
- if logged.size >= NUM_LOG_ONCE_KEYS && key.kind_of?(String)
53
- # The reason for preventing too many keys in `logged` is for
54
- # memory concerns.
55
- # The reason for checking the type of the key is that we always want
56
- # to allow symbols to log, since there are very few of them.
57
- # The assumption here is that you would NEVER pass dynamically-created
58
- # symbols, because you would never create symbols dynamically in the
59
- # first place, as that would already be a memory leak in most Rubies,
60
- # even if we didn't hang on to them all here.
61
- return
46
+ @already_logged_lock.synchronize do
47
+ return if @already_logged.include?(key)
48
+
49
+ if @already_logged.size >= NUM_LOG_ONCE_KEYS && key.kind_of?(String)
50
+ # The reason for preventing too many keys in `logged` is for
51
+ # memory concerns.
52
+ # The reason for checking the type of the key is that we always want
53
+ # to allow symbols to log, since there are very few of them.
54
+ # The assumption here is that you would NEVER pass dynamically-created
55
+ # symbols, because you would never create symbols dynamically in the
56
+ # first place, as that would already be a memory leak in most Rubies,
57
+ # even if we didn't hang on to them all here.
58
+ return
59
+ end
60
+
61
+ @already_logged[key] = true
62
62
  end
63
63
 
64
- logged[key] = true
65
64
  self.send(level, *msgs)
66
65
  end
67
66
 
@@ -148,7 +147,9 @@ module NewRelic
148
147
  end
149
148
 
150
149
  def clear_already_logged
151
- @already_logged = {}
150
+ @already_logged_lock.synchronize do
151
+ @already_logged = {}
152
+ end
152
153
  end
153
154
 
154
155
  def wants_stdout?
@@ -306,7 +306,7 @@ module NewRelic
306
306
  :description => 'Defines a host for communicating with New Relic via a proxy server.'
307
307
  },
308
308
  :proxy_port => {
309
- :default => nil,
309
+ :default => 8080,
310
310
  :allow_nil => true,
311
311
  :public => true,
312
312
  :type => Fixnum,
@@ -595,6 +595,12 @@ module NewRelic
595
595
  :type => Boolean,
596
596
  :description => 'Enable or disable active record instrumentation.'
597
597
  },
598
+ :disable_data_mapper => {
599
+ :default => false,
600
+ :public => true,
601
+ :type => Boolean,
602
+ :description => 'Enable or disable DataMapper instrumentation.'
603
+ },
598
604
  :disable_activejob => {
599
605
  :default => false,
600
606
  :public => true,
@@ -602,6 +608,30 @@ module NewRelic
602
608
  :dynamic_name => true,
603
609
  :description => 'Enable or disable ActiveJob instrumentation.'
604
610
  },
611
+ :disable_memcached => {
612
+ :default => value_of(:disable_memcache_instrumentation),
613
+ :public => true,
614
+ :type => Boolean,
615
+ :description => 'Enable or disable instrumentation for the memcached gem.'
616
+ },
617
+ :disable_memcache_client => {
618
+ :default => value_of(:disable_memcache_instrumentation),
619
+ :public => true,
620
+ :type => Boolean,
621
+ :description => 'Enable or disable instrumenation for the memcache-client gem.'
622
+ },
623
+ :disable_dalli => {
624
+ :default => value_of(:disable_memcache_instrumentation),
625
+ :public => true,
626
+ :type => Boolean,
627
+ :description => 'Enable or disable instrumentation for the dalli gem.'
628
+ },
629
+ :disable_dalli_cas_client => {
630
+ :default => value_of(:disable_memcache_instrumentation),
631
+ :public => true,
632
+ :type => Boolean,
633
+ :description => "Enable or disable instrumentation for the dalli gem's additional CAS client support."
634
+ },
605
635
  :disable_memcache_instrumentation => {
606
636
  :default => false,
607
637
  :public => true,
@@ -250,9 +250,10 @@ module NewRelic
250
250
  ]
251
251
 
252
252
  SQL_COMMENT_REGEX = Regexp.new('/\*.*?\*/', Regexp::MULTILINE).freeze
253
+ EMPTY_STRING = ''.freeze
253
254
 
254
255
  def parse_operation_from_query(sql)
255
- sql = sql.gsub(SQL_COMMENT_REGEX, '')
256
+ sql = sql.gsub(SQL_COMMENT_REGEX, EMPTY_STRING)
256
257
  if sql =~ /(\w+)/
257
258
  op = $1.downcase
258
259
  return op if KNOWN_OPERATIONS.include?(op)
@@ -0,0 +1,177 @@
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/metric_helper'
6
+
7
+ module NewRelic
8
+ module Agent
9
+ module Datastores
10
+
11
+ # Add Datastore tracing to a method. This properly generates the metrics
12
+ # for New Relic's Datastore features. It does not capture the actual
13
+ # query content into Transaction Traces. Use wrap if you want to provide
14
+ # that functionality.
15
+ #
16
+ # @param [Class] clazz the class to instrument
17
+ #
18
+ # @param [String, Symbol] method_name the name of instance method to
19
+ # instrument
20
+ #
21
+ # @param [String] product name of your datastore for use in metric naming, e.g. "Redis"
22
+ #
23
+ # @param [optional,String] operation the name of operation if different
24
+ # than the instrumented method name
25
+ #
26
+ # @api public
27
+ #
28
+ def self.trace(clazz, method_name, product, operation = method_name)
29
+ clazz.class_eval do
30
+ method_name_without_newrelic = "#{method_name}_without_newrelic"
31
+
32
+ if NewRelic::Helper.instance_methods_include?(clazz, method_name) &&
33
+ !NewRelic::Helper.instance_methods_include?(clazz, method_name_without_newrelic)
34
+
35
+ visibility = NewRelic::Helper.instance_method_visibility(clazz, method_name)
36
+
37
+ alias_method method_name_without_newrelic, method_name
38
+
39
+ define_method(method_name) do |*args, &blk|
40
+ metrics = MetricHelper.metrics_for(product, operation)
41
+ NewRelic::Agent::MethodTracer.trace_execution_scoped(metrics) do
42
+ send(method_name_without_newrelic, *args, &blk)
43
+ end
44
+ end
45
+
46
+ send visibility, method_name
47
+ send visibility, method_name_without_newrelic
48
+ end
49
+ end
50
+ end
51
+
52
+ # Wrap a call to a datastore and record New Relic Datastore metrics. This
53
+ # method can be used when a collection (i.e. table or model name) is
54
+ # known at runtime to be included in the metric naming. It is intended
55
+ # for situations that the simpler NewRelic::Agent::Datastores.trace can't
56
+ # properly handle.
57
+ #
58
+ # To use this, wrap the datastore operation in the block passed to wrap.
59
+ #
60
+ # NewRelic::Agent::Datastores.wrap("FauxDB", "find", "items") do
61
+ # FauxDB.find(query)
62
+ # end
63
+ #
64
+ # @param [String] product the datastore name for use in metric naming,
65
+ # e.g. "FauxDB"
66
+ #
67
+ # @param [String,Symbol] operation the name of operation (e.g. "select"),
68
+ # often named after the method that's being instrumented.
69
+ #
70
+ # @param [optional, String] collection the collection name for use in
71
+ # statement-level metrics (i.e. table or model name)
72
+ #
73
+ # @param [Proc,#call] callback proc or other callable to invoke after
74
+ # running the datastore block. Receives three arguments: result of the
75
+ # yield, the most specific (scoped) metric name, and elapsed time of the
76
+ # call. An example use is attaching SQL to Transaction Traces at the end
77
+ # of a wrapped datastore call.
78
+ #
79
+ # callback = Proc.new do |result, metrics, elapsed|
80
+ # NewRelic::Agent::Datastores.notice_sql(query, metrics, elapsed)
81
+ # end
82
+ #
83
+ # NewRelic::Agent::Datastores.wrap("FauxDB", "find", "items", callback) do
84
+ # FauxDB.find(query)
85
+ # end
86
+ #
87
+ # **NOTE: THERE ARE SECURITY CONCERNS WHEN CAPTURING SQL!**
88
+ # New Relic's Transaction Tracing and Slow SQL features will
89
+ # attempt to apply obfuscation to the passed queries, but it is possible
90
+ # for a query format to be unsupported and result in exposing user
91
+ # information embedded within captured queries.
92
+ #
93
+ # @api public
94
+ #
95
+ def self.wrap(product, operation, collection = nil, callback = nil)
96
+ return yield unless operation
97
+
98
+ metrics = MetricHelper.metrics_for(product, operation, collection)
99
+ scoped_metric = metrics.first
100
+ NewRelic::Agent::MethodTracer.trace_execution_scoped(metrics) do
101
+ t0 = Time.now
102
+ begin
103
+ result = yield
104
+ ensure
105
+ if callback
106
+ elapsed_time = (Time.now - t0).to_f
107
+ callback.call(result, scoped_metric, elapsed_time)
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ # Wrapper for simplifying attaching SQL queries during a transaction.
114
+ #
115
+ # If you are recording non-SQL data, please use the notice_statement
116
+ # method instead.
117
+ #
118
+ # NewRelic::Agent::Datastores.notice_sql(query, metrics, elapsed)
119
+ #
120
+ # @param [String] query the SQL text to be captured. Note that depending
121
+ # on user settings, this string will be run through obfuscation, but
122
+ # some dialects of SQL (or non-SQL queries) are not guaranteed to be
123
+ # properly obfuscated by these routines!
124
+ #
125
+ # @param [String] scoped_metric The most specific metric relating to this
126
+ # query. Typically the result of
127
+ # NewRelic::Agent::Datastores::MetricHelper#metrics_for
128
+ #
129
+ # @param [Float] elapsed the elapsed time during query execution
130
+ #
131
+ # **NOTE: THERE ARE SECURITY CONCERNS WHEN CAPTURING SQL!**
132
+ # New Relic's Transaction Tracing and Slow SQL features will
133
+ # attempt to apply obfuscation to the passed queries, but it is possible
134
+ # for a query format to be unsupported and result in exposing user
135
+ # information embedded within captured queries.
136
+ #
137
+ def self.notice_sql(query, scoped_metric, elapsed)
138
+ agent = NewRelic::Agent.instance
139
+ agent.transaction_sampler.notice_sql(query, nil, elapsed)
140
+ agent.sql_sampler.notice_sql(query, scoped_metric, nil, elapsed)
141
+ nil
142
+ end
143
+
144
+ # Wrapper for simplifying attaching non-SQL data statements to a
145
+ # transaction. For instance, Mongo or CQL queries, Memcached or Redis
146
+ # keys would all be appropriate data to attach as statements.
147
+ #
148
+ # Data passed to this method is NOT obfuscated by New Relic, so please
149
+ # ensure that user information is obfuscated if the agent setting
150
+ # `transaction_tracer.record_sql` is set to `obfuscated`
151
+ #
152
+ # NewRelic::Agent::Datastores.notice_statement("key", elapsed)
153
+ #
154
+ # @param [String] statement text of the statement to capture.
155
+ #
156
+ # @param [Float] elapsed the elapsed time during query execution
157
+ #
158
+ # **NOTE: THERE ARE SECURITY CONCERNS WHEN CAPTURING STATEMENTS!**
159
+ # This method will properly ignore statements when the user has turned
160
+ # off capturing queries, but it is not able to obfuscate arbitrary data!
161
+ # To prevent exposing user information embedded in captured queries,
162
+ # please ensure all data passed to this method is safe to transmit to
163
+ # New Relic.
164
+ #
165
+ def self.notice_statement(statement, elapsed)
166
+ # Settings may change eventually, but for now we follow the same
167
+ # capture rules as SQL for non-SQL statements.
168
+ return unless NewRelic::Agent::Database.should_record_sql?
169
+
170
+ agent = NewRelic::Agent.instance
171
+ agent.transaction_sampler.notice_nosql_statement(statement, elapsed)
172
+ nil
173
+ end
174
+
175
+ end
176
+ end
177
+ end