newrelic_rpm 3.9.1.236 → 3.9.2.239

Sign up to get free protection for your applications and to get access to all the features.
Files changed (220) hide show
  1. data.tar.gz.sig +2 -4
  2. data/CHANGELOG +96 -2
  3. data/lib/new_relic/agent.rb +47 -4
  4. data/lib/new_relic/agent/agent.rb +51 -26
  5. data/lib/new_relic/agent/agent_logger.rb +4 -0
  6. data/lib/new_relic/agent/configuration.rb +2 -32
  7. data/lib/new_relic/agent/configuration/default_source.rb +153 -118
  8. data/lib/new_relic/agent/configuration/dotted_hash.rb +52 -0
  9. data/lib/new_relic/agent/configuration/environment_source.rb +1 -1
  10. data/lib/new_relic/agent/configuration/manager.rb +101 -2
  11. data/lib/new_relic/agent/configuration/manual_source.rb +17 -0
  12. data/lib/new_relic/agent/configuration/server_source.rb +12 -4
  13. data/lib/new_relic/agent/configuration/yaml_source.rb +46 -22
  14. data/lib/new_relic/agent/cross_app_monitor.rb +1 -1
  15. data/lib/new_relic/agent/cross_app_tracing.rb +1 -1
  16. data/lib/new_relic/agent/database/obfuscation_helpers.rb +55 -14
  17. data/lib/new_relic/agent/database/obfuscator.rb +22 -7
  18. data/lib/new_relic/agent/database/postgres_explain_obfuscator.rb +6 -8
  19. data/lib/new_relic/agent/error_collector.rb +24 -16
  20. data/lib/new_relic/agent/event_loop.rb +189 -0
  21. data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +8 -17
  22. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +1 -1
  23. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +1 -1
  24. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +17 -16
  25. data/lib/new_relic/agent/instrumentation/ignore_actions.rb +41 -0
  26. data/lib/new_relic/agent/instrumentation/merb/controller.rb +0 -11
  27. data/lib/new_relic/agent/instrumentation/middleware_tracing.rb +1 -1
  28. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +0 -8
  29. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +1 -9
  30. data/lib/new_relic/agent/instrumentation/rails4/action_controller.rb +0 -18
  31. data/lib/new_relic/agent/instrumentation/rubyprof.rb +1 -1
  32. data/lib/new_relic/agent/instrumentation/sidekiq.rb +1 -1
  33. data/lib/new_relic/agent/instrumentation/sinatra.rb +12 -1
  34. data/lib/new_relic/agent/instrumentation/sinatra/transaction_namer.rb +1 -1
  35. data/lib/new_relic/agent/method_tracer.rb +33 -39
  36. data/lib/new_relic/agent/new_relic_service.rb +35 -156
  37. data/lib/new_relic/agent/new_relic_service/encoders.rb +34 -0
  38. data/lib/new_relic/agent/new_relic_service/json_marshaller.rb +50 -0
  39. data/lib/new_relic/agent/new_relic_service/marshaller.rb +52 -0
  40. data/lib/new_relic/agent/new_relic_service/pruby_marshaller.rb +52 -0
  41. data/lib/new_relic/agent/threading/backtrace_node.rb +1 -1
  42. data/lib/new_relic/agent/traced_method_stack.rb +16 -2
  43. data/lib/new_relic/agent/transaction.rb +0 -4
  44. data/lib/new_relic/collection_helper.rb +2 -2
  45. data/lib/new_relic/control/frameworks/rails.rb +3 -0
  46. data/lib/new_relic/control/instrumentation.rb +6 -2
  47. data/lib/new_relic/json_wrapper.rb +47 -25
  48. data/lib/new_relic/language_support.rb +0 -4
  49. data/lib/new_relic/latest_changes.rb +2 -2
  50. data/lib/new_relic/rack/developer_mode.rb +4 -3
  51. data/lib/new_relic/recipes/capistrano3.rb +2 -2
  52. data/lib/new_relic/recipes/capistrano_legacy.rb +1 -1
  53. data/lib/new_relic/timer_lib.rb +1 -1
  54. data/lib/new_relic/version.rb +2 -2
  55. data/lib/tasks/config.html.erb +28 -0
  56. data/lib/tasks/config.rake +134 -0
  57. data/lib/tasks/config.text.erb +7 -0
  58. data/lib/tasks/install.rake +0 -63
  59. data/newrelic.yml +7 -0
  60. data/test/active_record_fixtures.rb +4 -4
  61. data/test/agent_helper.rb +58 -18
  62. data/test/environments/lib/environments/runner.rb +1 -1
  63. data/test/environments/rails21/Gemfile +1 -1
  64. data/test/environments/rails21/config/boot.rb +1 -1
  65. data/test/environments/rails22/Gemfile +1 -1
  66. data/test/environments/rails22/config/boot.rb +1 -1
  67. data/test/environments/rails23/config/boot.rb +2 -2
  68. data/test/environments/rails30/Gemfile +1 -1
  69. data/test/environments/rails31/Gemfile +1 -1
  70. data/test/environments/rails32/Gemfile +1 -1
  71. data/test/environments/rails40/Gemfile +1 -1
  72. data/test/environments/rails41/Gemfile +1 -1
  73. data/test/fixtures/cross_agent_tests/labels.json +104 -0
  74. data/test/fixtures/cross_agent_tests/sql_obfuscation/README.md +23 -0
  75. data/test/fixtures/cross_agent_tests/sql_obfuscation/back_quoted_identifiers.mysql.obfuscated +1 -0
  76. data/test/fixtures/cross_agent_tests/sql_obfuscation/back_quoted_identifiers.mysql.sql +1 -0
  77. data/test/fixtures/cross_agent_tests/sql_obfuscation/comment_delimiters_in_strings.obfuscated +1 -0
  78. data/test/fixtures/cross_agent_tests/sql_obfuscation/comment_delimiters_in_strings.sql +1 -0
  79. data/test/fixtures/cross_agent_tests/sql_obfuscation/double_quoted_identifiers.postgres.obfuscated +1 -0
  80. data/test/fixtures/cross_agent_tests/sql_obfuscation/double_quoted_identifiers.postgres.sql +1 -0
  81. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_line_comment_in_string.obfuscated +2 -0
  82. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_line_comment_in_string.sql +2 -0
  83. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_line_comments_with_quotes.obfuscated +1 -0
  84. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_line_comments_with_quotes.sql +2 -0
  85. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_cstyle.obfuscated +1 -0
  86. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_cstyle.sql +1 -0
  87. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_doubledash.obfuscated +2 -0
  88. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_doubledash.sql +2 -0
  89. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_hash.obfuscated +1 -0
  90. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_hash.sql +1 -0
  91. data/test/fixtures/cross_agent_tests/sql_obfuscation/escape_string_constants.postgres.obfuscated +1 -0
  92. data/test/fixtures/cross_agent_tests/sql_obfuscation/escape_string_constants.postgres.sql +4 -0
  93. data/test/fixtures/cross_agent_tests/sql_obfuscation/malformed/unterminated_double_quoted_string.mysql.sql +1 -0
  94. data/test/fixtures/cross_agent_tests/sql_obfuscation/malformed/unterminated_single_quoted_string.sql +1 -0
  95. data/test/fixtures/cross_agent_tests/sql_obfuscation/mixed_comments_and_quotes.obfuscated +1 -0
  96. data/test/fixtures/cross_agent_tests/sql_obfuscation/mixed_comments_and_quotes.sql +2 -0
  97. data/test/fixtures/cross_agent_tests/sql_obfuscation/mixed_quotes_comments_and_newlines.obfuscated +1 -0
  98. data/test/fixtures/cross_agent_tests/sql_obfuscation/mixed_quotes_comments_and_newlines.sql +4 -0
  99. data/test/fixtures/cross_agent_tests/sql_obfuscation/mixed_quotes_end_of_line_comments.obfuscated +1 -0
  100. data/test/fixtures/cross_agent_tests/sql_obfuscation/mixed_quotes_end_of_line_comments.sql +3 -0
  101. data/test/fixtures/cross_agent_tests/sql_obfuscation/multiple_literal_types.mysql.obfuscated +1 -0
  102. data/test/fixtures/cross_agent_tests/sql_obfuscation/multiple_literal_types.mysql.sql +1 -0
  103. data/test/fixtures/cross_agent_tests/sql_obfuscation/numbers_in_identifiers.obfuscated +1 -0
  104. data/test/fixtures/cross_agent_tests/sql_obfuscation/numbers_in_identifiers.sql +1 -0
  105. data/test/fixtures/cross_agent_tests/sql_obfuscation/numeric_literals.obfuscated +1 -0
  106. data/test/fixtures/cross_agent_tests/sql_obfuscation/numeric_literals.sql +1 -0
  107. data/test/fixtures/cross_agent_tests/sql_obfuscation/quote_delimiters_in_comments.obfuscated +1 -0
  108. data/test/fixtures/cross_agent_tests/sql_obfuscation/quote_delimiters_in_comments.sql +1 -0
  109. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_double_quoted.mysql.obfuscated +1 -0
  110. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_double_quoted.mysql.sql +1 -0
  111. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_single_quoted.obfuscated +1 -0
  112. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_single_quoted.sql +1 -0
  113. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_backslash_and_twin_single_quotes.obfuscated +1 -0
  114. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_backslash_and_twin_single_quotes.sql +4 -0
  115. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_double_quote.obfuscated +1 -0
  116. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_double_quote.sql +1 -0
  117. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_newline.obfuscated +1 -0
  118. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_newline.sql +2 -0
  119. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_single_quote.mysql.obfuscated +1 -0
  120. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_single_quote.mysql.sql +1 -0
  121. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_escaped_quotes.mysql.obfuscated +1 -0
  122. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_escaped_quotes.mysql.sql +1 -0
  123. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_backslash.obfuscated +1 -0
  124. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_backslash.sql +4 -0
  125. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_backslash.mysql.obfuscated +1 -0
  126. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_backslash.mysql.sql +1 -0
  127. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_backslash_single_quoted.obfuscated +1 -0
  128. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_backslash_single_quoted.sql +1 -0
  129. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_quote.obfuscated +1 -0
  130. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_quote.sql +1 -0
  131. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_twin_single_quotes.obfuscated +1 -0
  132. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_twin_single_quotes.sql +1 -0
  133. data/test/multiverse/lib/multiverse/output_collector.rb +1 -1
  134. data/test/multiverse/lib/multiverse/runner.rb +1 -1
  135. data/test/multiverse/lib/multiverse/suite.rb +19 -4
  136. data/test/multiverse/suites/agent_only/audit_log_test.rb +1 -38
  137. data/test/multiverse/suites/agent_only/collector_exception_handling_test.rb +25 -35
  138. data/test/multiverse/suites/agent_only/config/newrelic.yml +2 -0
  139. data/test/multiverse/suites/agent_only/encoding_handling_test.rb +1 -0
  140. data/test/multiverse/suites/agent_only/harvest_timestamps_test.rb +1 -1
  141. data/test/multiverse/suites/agent_only/keepalive_test.rb +29 -0
  142. data/test/multiverse/suites/agent_only/labels_test.rb +89 -0
  143. data/test/multiverse/suites/agent_only/marshaling_test.rb +1 -3
  144. data/test/multiverse/suites/agent_only/service_timeout_test.rb +1 -1
  145. data/test/multiverse/suites/agent_only/start_up_test.rb +9 -1
  146. data/test/multiverse/suites/capistrano/config/deploy.rb +6 -2
  147. data/test/multiverse/suites/capistrano/deployment_test.rb +12 -4
  148. data/test/multiverse/suites/config_file_loading/config_file_loading_test.rb +29 -1
  149. data/test/multiverse/suites/curb/Envfile +6 -2
  150. data/test/multiverse/suites/datamapper/Envfile +0 -4
  151. data/test/multiverse/suites/deferred_instrumentation/Envfile +0 -4
  152. data/test/multiverse/suites/deferred_instrumentation/sinatra_test.rb +1 -1
  153. data/test/multiverse/suites/excon/Envfile +5 -4
  154. data/test/multiverse/suites/excon/excon_test.rb +1 -1
  155. data/test/multiverse/suites/httpclient/Envfile +0 -4
  156. data/test/multiverse/suites/marshalling/Envfile +12 -0
  157. data/test/multiverse/suites/marshalling/config/newrelic.yml +20 -0
  158. data/test/multiverse/suites/marshalling/marshalling_test.rb +60 -0
  159. data/test/multiverse/suites/mongo/helpers/mongo_operation_tests.rb +1 -1
  160. data/test/multiverse/suites/mongo/helpers/mongo_replica_set.rb +1 -1
  161. data/test/multiverse/suites/mongo/helpers/mongo_server.rb +4 -4
  162. data/test/multiverse/suites/padrino/Envfile +0 -5
  163. data/test/multiverse/suites/padrino/padrino_test.rb +1 -1
  164. data/test/multiverse/suites/rack/rack_auto_instrumentation_test.rb +1 -1
  165. data/test/multiverse/suites/rails/gc_instrumentation_test.rb +2 -1
  166. data/test/multiverse/suites/rails/ignore_test.rb +22 -0
  167. data/test/multiverse/suites/rails/rails2_app/config/boot.rb +2 -2
  168. data/test/multiverse/suites/rails/rails2_app/config/routes.rb +1 -0
  169. data/test/multiverse/suites/resque/Envfile +0 -4
  170. data/test/multiverse/suites/sequel/Envfile +0 -5
  171. data/test/multiverse/suites/sinatra/sinatra_classic_test.rb +1 -1
  172. data/test/multiverse/suites/sinatra/sinatra_modular_test.rb +1 -1
  173. data/test/multiverse/suites/sinatra/sinatra_test_cases.rb +22 -0
  174. data/test/multiverse/suites/typhoeus/Envfile +1 -4
  175. data/test/new_relic/agent/agent/start_worker_thread_test.rb +1 -13
  176. data/test/new_relic/agent/agent_logger_test.rb +11 -0
  177. data/test/new_relic/agent/agent_test.rb +43 -20
  178. data/test/new_relic/agent/audit_logger_test.rb +7 -3
  179. data/test/new_relic/agent/commands/thread_profiler_session_test.rb +0 -1
  180. data/test/new_relic/agent/commands/xray_session_collection_test.rb +1 -1
  181. data/test/new_relic/agent/configuration/dotted_hash_test.rb +53 -0
  182. data/test/new_relic/agent/configuration/manager_test.rb +99 -6
  183. data/test/new_relic/agent/configuration/manual_source_test.rb +18 -0
  184. data/test/new_relic/agent/configuration/orphan_configuration_test.rb +1 -1
  185. data/test/new_relic/agent/configuration/yaml_source_test.rb +8 -4
  186. data/test/new_relic/agent/database/sql_obfuscation_test.rb +76 -0
  187. data/test/new_relic/agent/database_test.rb +2 -38
  188. data/test/new_relic/agent/error_collector/notice_error_test.rb +21 -3
  189. data/test/new_relic/agent/error_collector_test.rb +15 -2
  190. data/test/new_relic/agent/event_loop_test.rb +202 -0
  191. data/test/new_relic/agent/instrumentation/active_record_helper_test.rb +4 -0
  192. data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +283 -182
  193. data/test/new_relic/agent/method_tracer_test.rb +1 -2
  194. data/test/new_relic/agent/new_relic_service_test.rb +83 -27
  195. data/test/new_relic/agent/pipe_channel_manager_test.rb +6 -6
  196. data/test/new_relic/agent/rpm_agent_test.rb +1 -8
  197. data/test/new_relic/agent/sql_sampler_test.rb +10 -8
  198. data/test/new_relic/agent/threading/backtrace_service_test.rb +1 -1
  199. data/test/new_relic/agent/traced_method_stack_test.rb +45 -13
  200. data/test/new_relic/agent/transaction_sample_builder_test.rb +1 -2
  201. data/test/new_relic/agent/transaction_test.rb +3 -3
  202. data/test/new_relic/agent_test.rb +47 -8
  203. data/test/new_relic/collection_helper_test.rb +5 -5
  204. data/test/new_relic/control/instrumentation_test.rb +56 -0
  205. data/test/new_relic/control_test.rb +4 -3
  206. data/test/new_relic/fake_collector.rb +7 -2
  207. data/test/new_relic/http_client_test_cases.rb +4 -4
  208. data/test/new_relic/latest_changes_test.rb +3 -3
  209. data/test/new_relic/transaction_sample/segment_test.rb +0 -1
  210. data/test/new_relic/transaction_sample_test.rb +19 -2
  211. data/test/performance/lib/performance/runner.rb +4 -4
  212. data/test/performance/suites/marshalling.rb +46 -30
  213. data/test/performance/suites/sql_obfuscation.rb +30 -0
  214. data/test/test_helper.rb +1 -1
  215. data/ui/helpers/developer_mode_helper.rb +2 -2
  216. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/java.rb +1 -1
  217. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/view.rb +1 -1
  218. metadata +84 -3
  219. metadata.gz.sig +0 -0
  220. data/test/environments/rails23/config/environments/development.rb +0 -11
@@ -11,13 +11,11 @@ module NewRelic
11
11
  module PostgresExplainObfuscator
12
12
  extend self
13
13
 
14
- extend ObfuscationHelpers
15
-
16
- SINGLE_OR_DOUBLE_QUOTES = Regexp.new([
17
- ObfuscationHelpers::SINGLE_QUOTES.source,
18
- ObfuscationHelpers::DOUBLE_QUOTES.source
19
- ].join('|')).freeze
20
- LABEL_LINE_REGEX = /^([^:\n]*:\s+).*$/.freeze
14
+ # Note that this regex can't be shared with the ones in the
15
+ # Database::Obfuscator class because here we don't look for
16
+ # backslash-escaped strings (and those regexes are backwards).
17
+ QUOTED_STRINGS_REGEX = /'(?:[^']|'')*'|"(?:[^"]|"")*"/
18
+ LABEL_LINE_REGEX = /^([^:\n]*:\s+).*$/.freeze
21
19
 
22
20
  def obfuscate(explain)
23
21
  # First, we replace all single-quoted strings.
@@ -32,7 +30,7 @@ module NewRelic
32
30
  # Note also that we make no special provisions for backslash-escaped
33
31
  # single quotes (\') because these are canonicalized to two single
34
32
  # quotes ('') in the explain output.
35
- explain.gsub!(SINGLE_OR_DOUBLE_QUOTES) do |match|
33
+ explain.gsub!(QUOTED_STRINGS_REGEX) do |match|
36
34
  match.start_with?('"') ? match : '?'
37
35
  end
38
36
 
@@ -55,24 +55,33 @@ module NewRelic
55
55
  !enabled?
56
56
  end
57
57
 
58
- # Returns the error filter proc that is used to check if an
59
- # error should be reported. When given a block, resets the
60
- # filter to the provided block. The define_method() is used to
61
- # wrap the block in a lambda so return statements don't result in a
62
- # LocalJump exception.
63
- def ignore_error_filter(&block)
58
+ # We store the passed block in both an ivar on the class, and implicitly
59
+ # within the body of the ignore_filter_proc method intentionally here.
60
+ # The define_method trick is needed to get around the fact that users may
61
+ # call 'return' from within their filter blocks, which would otherwise
62
+ # result in a LocalJumpError.
63
+ #
64
+ # The raw block is also stored in an instance variable so that we can
65
+ # return it later in its original form.
66
+ #
67
+ # This is all done at the class level in order to avoid the case where
68
+ # the user sets up an ignore filter on one instance of the ErrorCollector,
69
+ # and then that instance subsequently gets discarded during agent startup.
70
+ # (For example, if the agent is initially disabled, and then gets enabled
71
+ # via a call to manual_start later on.)
72
+ #
73
+ def self.ignore_error_filter=(block)
74
+ @ignore_filter = block
64
75
  if block
65
- self.class.class_eval { define_method(:ignore_filter_proc, &block) }
66
- @ignore_filter = method(:ignore_filter_proc)
67
- else
68
- @ignore_filter
76
+ define_method(:ignore_filter_proc, &block)
77
+ elsif method_defined?(:ignore_filter_proc)
78
+ undef :ignore_filter_proc
69
79
  end
80
+ @ignore_filter
70
81
  end
71
82
 
72
- # Only used from testing scenarios since can't tell difference between
73
- # having a nil filter passed and no block for retrieval on main method.
74
- def clear_ignore_error_filter
75
- @ignore_filter = nil
83
+ def self.ignore_error_filter
84
+ @ignore_filter
76
85
  end
77
86
 
78
87
  # errors is an array of Exception Class Names
@@ -90,8 +99,7 @@ module NewRelic
90
99
  # Checks the provided error against the error filter, if there
91
100
  # is an error filter
92
101
  def filtered_by_error_filter?(error)
93
- return unless @ignore_filter
94
- !@ignore_filter.call(error)
102
+ respond_to?(:ignore_filter_proc) && !ignore_filter_proc(error)
95
103
  end
96
104
 
97
105
  # Checks the array of error names and the error filter against
@@ -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 'thread'
6
+
7
+ module NewRelic
8
+ module Agent
9
+ class EventLoop
10
+ class Timer
11
+ attr_reader :next_fire_time, :event, :interval, :last_fired_at
12
+
13
+ def initialize(interval, event, repeat=false)
14
+ @interval = interval
15
+ @event = event
16
+ @repeat = repeat
17
+ @started_at = Time.now
18
+ @last_fired_at = nil
19
+ reschedule
20
+ end
21
+
22
+ def reschedule
23
+ @next_fire_time = calculate_next_fire_time
24
+ end
25
+
26
+ def advance(amount)
27
+ @next_fire_time -= amount
28
+ end
29
+
30
+ def last_interval_start
31
+ @last_fired_at || @started_at
32
+ end
33
+
34
+ def calculate_next_fire_time
35
+ now = Time.now
36
+ return now if @interval == 0
37
+ fire_time = @last_fired_at || now
38
+ while fire_time <= now
39
+ fire_time += @interval
40
+ end
41
+ fire_time
42
+ end
43
+
44
+ def set_fired_time
45
+ @last_fired_at = Time.now
46
+ end
47
+
48
+ def due?(now=Time.now)
49
+ now >= @next_fire_time
50
+ end
51
+
52
+ def finished?
53
+ !@repeat && @last_fired_at
54
+ end
55
+ end
56
+
57
+ def initialize
58
+ @self_pipe_rd, @self_pipe_wr = IO.pipe
59
+ @event_queue = Queue.new
60
+ @stopped = false
61
+ @timers = {}
62
+
63
+ @subscriptions = Hash.new { |h,k| h[k] = [] }
64
+ @subscriptions[:__add_timer] << Proc.new { |t| set_timer(t) }
65
+ @subscriptions[:__add_event] << Proc.new { |e, blk| @subscriptions[e] << blk }
66
+ end
67
+
68
+ def set_timer(timer)
69
+ existing_timer = @timers[timer.event]
70
+
71
+ if existing_timer
72
+ elapsed_interval = Time.now - existing_timer.last_interval_start
73
+ timer.advance(elapsed_interval)
74
+ end
75
+
76
+ @timers[timer.event] = timer
77
+
78
+ fire_timer(timer)
79
+ end
80
+
81
+ def next_timeout
82
+ return nil if @timers.empty?
83
+ timeout = @timers.values.map(&:next_fire_time).min - Time.now
84
+ timeout < 0 ? 0 : timeout
85
+ end
86
+
87
+ def stopped?
88
+ @stopped
89
+ end
90
+
91
+ def stop
92
+ @stopped = true
93
+ wakeup
94
+ end
95
+
96
+ def run
97
+ ::NewRelic::Agent.logger.debug "Running event loop"
98
+ while !stopped?
99
+ run_once
100
+ end
101
+ end
102
+
103
+ def run_once(nonblock=false)
104
+ wait_to_run(nonblock)
105
+
106
+ prune_timers
107
+ fire_timers
108
+
109
+ until @event_queue.empty?
110
+ evt, args = @event_queue.pop
111
+ dispatch_event(evt, args)
112
+ reschedule_timer_for_event(evt)
113
+ end
114
+ end
115
+
116
+ def wait_to_run(nonblock)
117
+ timeout = nonblock ? 0 : next_timeout
118
+ ready = select([@self_pipe_rd], nil, nil, timeout)
119
+
120
+ if ready && ready[0] && ready[0][0] && ready[0][0] == @self_pipe_rd
121
+ @self_pipe_rd.read(1)
122
+ end
123
+ end
124
+
125
+ def fire_timers
126
+ @timers.each do |event, timer|
127
+ fire_timer(timer)
128
+ end
129
+ end
130
+
131
+ def fire_timer(timer)
132
+ if timer.due?
133
+ @event_queue << [timer.event]
134
+ timer.set_fired_time
135
+ end
136
+ end
137
+
138
+ def prune_timers
139
+ @timers.delete_if { |e, t| t.finished? }
140
+ end
141
+
142
+ def dispatch_event(event, args)
143
+ NewRelic::Agent.logger.debug("EventLoop: Dispatching event '#{event}' with #{@subscriptions[event].size} callback(s).")
144
+
145
+ errors = []
146
+ @subscriptions[event].each do |s|
147
+ begin
148
+ s.call(*args)
149
+ rescue NewRelic::Agent::ForceRestartException, NewRelic::Agent::ForceDisconnectException
150
+ raise
151
+ rescue => e
152
+ errors << e
153
+ end
154
+ end
155
+
156
+ if !errors.empty?
157
+ ::NewRelic::Agent.logger.error "#{errors.size} error(s) running task for event '#{event}' in Agent Event Loop:", *errors
158
+ end
159
+ end
160
+
161
+ def reschedule_timer_for_event(e)
162
+ @timers[e].reschedule if @timers[e]
163
+ end
164
+
165
+ def on(event, &blk)
166
+ fire(:__add_event, event, blk)
167
+ end
168
+
169
+ def fire(event, *args)
170
+ @event_queue << [event, args]
171
+ wakeup
172
+ end
173
+
174
+ def fire_every(interval, event)
175
+ ::NewRelic::Agent.logger.debug "Firing event #{event} every #{interval} seconds."
176
+ fire(:__add_timer, Timer.new(interval, event, true))
177
+ end
178
+
179
+ def fire_after(interval, event)
180
+ ::NewRelic::Agent.logger.debug "Firing event #{event} after #{interval} seconds."
181
+ fire(:__add_timer, Timer.new(interval, event, false))
182
+ end
183
+
184
+ def wakeup
185
+ @self_pipe_wr << '.'
186
+ end
187
+ end
188
+ end
189
+ 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
  require 'new_relic/agent/instrumentation/evented_subscriber'
5
+ require 'new_relic/agent/instrumentation/ignore_actions'
5
6
 
6
7
  module NewRelic
7
8
  module Agent
@@ -92,32 +93,22 @@ module NewRelic
92
93
  end
93
94
 
94
95
  def ignored?
95
- _is_filtered?('do_not_trace')
96
+ _is_filtered?(ControllerInstrumentation::NR_DO_NOT_TRACE_KEY)
96
97
  end
97
98
 
98
99
  def apdex_ignored?
99
- _is_filtered?('ignore_apdex')
100
+ _is_filtered?(ControllerInstrumentation::NR_IGNORE_APDEX_KEY)
100
101
  end
101
102
 
102
103
  def enduser_ignored?
103
- _is_filtered?('ignore_enduser')
104
+ _is_filtered?(ControllerInstrumentation::NR_IGNORE_ENDUSER_KEY)
104
105
  end
105
106
 
106
- # FIXME: shamelessly ripped from ControllerInstrumentation
107
107
  def _is_filtered?(key)
108
- if @controller_class.respond_to? :newrelic_read_attr
109
- ignore_actions = @controller_class.newrelic_read_attr(key)
110
- end
111
-
112
- case ignore_actions
113
- when nil; false
114
- when Hash
115
- only_actions = Array(ignore_actions[:only])
116
- except_actions = Array(ignore_actions[:except])
117
- only_actions.include?(metric_action.to_sym) || (except_actions.any? && !except_actions.include?(metric_action.to_sym))
118
- else
119
- true
120
- end
108
+ NewRelic::Agent::Instrumentation::IgnoreActions.is_filtered?(
109
+ key,
110
+ @controller_class,
111
+ metric_action)
121
112
  end
122
113
 
123
114
  def to_s
@@ -8,7 +8,7 @@ module NewRelic
8
8
  module_function
9
9
 
10
10
  def metric_for_name(name)
11
- return unless name
11
+ return unless name && name.respond_to?(:split)
12
12
  parts = name.split(' ')
13
13
  if parts.size == 2
14
14
  model = parts.first
@@ -84,7 +84,7 @@ module NewRelic
84
84
  return unless event.payload[:connection_id]
85
85
 
86
86
  connections = ::ActiveRecord::Base.connection_handler.connection_pool_list.map { |handler| handler.connections }.flatten
87
- connection = connections.detect { |connection| connection.object_id == event.payload[:connection_id] }
87
+ connection = connections.detect { |cnxn| cnxn.object_id == event.payload[:connection_id] }
88
88
 
89
89
  connection.instance_variable_get(:@config) if connection
90
90
  end
@@ -4,6 +4,7 @@
4
4
 
5
5
  require 'new_relic/agent/transaction'
6
6
  require 'new_relic/agent/instrumentation/queue_time'
7
+ require 'new_relic/agent/instrumentation/ignore_actions'
7
8
  module NewRelic
8
9
  module Agent
9
10
  # @api public
@@ -45,10 +46,10 @@ module NewRelic
45
46
  def perform_action_with_newrelic_trace(*args); yield; end
46
47
  end
47
48
 
48
- NR_DO_NOT_TRACE_KEY = 'do_not_trace'.freeze unless defined?(NR_DO_NOT_TRACE_KEY)
49
- NR_IGNORE_APDEX_KEY = 'ignore_apdex'.freeze unless defined?(NR_IGNORE_APDEX_KEY)
50
- NR_IGNORE_ENDUSER_KEY = 'ignore_enduser'.freeze unless defined?(NR_IGNORE_ENDUSER_KEY)
51
- NR_DEFAULT_OPTIONS = {}.freeze unless defined?(NR_DEFAULT_OPTIONS)
49
+ NR_DO_NOT_TRACE_KEY = :'@do_not_trace' unless defined?(NR_DO_NOT_TRACE_KEY )
50
+ NR_IGNORE_APDEX_KEY = :'@ignore_apdex' unless defined?(NR_IGNORE_APDEX_KEY )
51
+ NR_IGNORE_ENDUSER_KEY = :'@ignore_enduser' unless defined?(NR_IGNORE_ENDUSER_KEY)
52
+ NR_DEFAULT_OPTIONS = {}.freeze unless defined?(NR_DEFAULT_OPTIONS )
52
53
 
53
54
  # @api public
54
55
  module ClassMethods
@@ -88,11 +89,11 @@ module NewRelic
88
89
  # Should be monkey patched into the controller class implemented
89
90
  # with the inheritable attribute mechanism.
90
91
  def newrelic_write_attr(attr_name, value) # :nodoc:
91
- instance_variable_set "@#{attr_name}", value
92
+ instance_variable_set(attr_name, value)
92
93
  end
93
94
 
94
95
  def newrelic_read_attr(attr_name) # :nodoc:
95
- instance_variable_get "@#{attr_name}"
96
+ instance_variable_get(attr_name)
96
97
  end
97
98
 
98
99
  # Add transaction tracing to the given method. This will treat
@@ -329,7 +330,7 @@ module NewRelic
329
330
  state = NewRelic::Agent::TransactionState.tl_get
330
331
  state.request = newrelic_request(args)
331
332
 
332
- # Skip instrumentation based on the value of 'do_not_trace' and if
333
+ # Skip instrumentation based on the value of 'do_not_trace?' and if
333
334
  # we aren't calling directly with a block.
334
335
  if !block_given? && do_not_trace?
335
336
  state.current_transaction.ignore! if state.current_transaction
@@ -439,18 +440,18 @@ module NewRelic
439
440
  end
440
441
 
441
442
  # Filter out a request if it matches one of our parameters for
442
- # ignoring it - the key is either 'do_not_trace' or 'ignore_apdex'
443
+ # ignoring it - the key is either NR_DO_NOT_TRACE_KEY or NR_IGNORE_APDEX_KEY
443
444
  def _is_filtered?(key)
444
- ignore_actions = self.class.newrelic_read_attr(key) if self.class.respond_to? :newrelic_read_attr
445
- case ignore_actions
446
- when nil; false
447
- when Hash
448
- only_actions = Array(ignore_actions[:only])
449
- except_actions = Array(ignore_actions[:except])
450
- only_actions.include?(action_name.to_sym) || (except_actions.any? && !except_actions.include?(action_name.to_sym))
445
+ name = if respond_to?(:action_name)
446
+ action_name
451
447
  else
452
- true
448
+ :'[action_name_missing]'
453
449
  end
450
+
451
+ NewRelic::Agent::Instrumentation::IgnoreActions.is_filtered?(
452
+ key,
453
+ self.class,
454
+ name)
454
455
  end
455
456
 
456
457
  def detect_queue_start_time(state)
@@ -0,0 +1,41 @@
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 Instrumentation
8
+ module IgnoreActions
9
+ def self.is_filtered?(key, klass, action_name)
10
+ # We'll walk the superclass chain and see if
11
+ # any class says 'yes, filter this one'.
12
+
13
+ while klass.respond_to? :newrelic_read_attr
14
+ ignore_actions = klass.newrelic_read_attr(key)
15
+
16
+ should_filter = case ignore_actions
17
+ when Hash
18
+ only_actions = Array(ignore_actions[:only])
19
+ except_actions = Array(ignore_actions[:except])
20
+ action_name = action_name.to_sym
21
+
22
+ only_actions.include?(action_name) || (!except_actions.empty? && !except_actions.include?(action_name))
23
+ else
24
+ !!ignore_actions
25
+ end
26
+
27
+ return true if should_filter
28
+
29
+ # Nothing so far says we should filter,
30
+ # so keep checking up the superclass chain.
31
+ klass = klass.superclass
32
+ end
33
+
34
+ # Getting here means that no class filtered this.
35
+ false
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+