newrelic_rpm 3.11.2.286 → 3.12.0.288

Sign up to get free protection for your applications and to get access to all the features.
Files changed (269) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -2
  3. data/.yardopts +2 -0
  4. data/CHANGELOG +39 -4
  5. data/README.md +4 -2
  6. data/lib/new_relic/agent.rb +229 -214
  7. data/lib/new_relic/agent/agent.rb +23 -12
  8. data/lib/new_relic/agent/attribute_filter.rb +242 -0
  9. data/lib/new_relic/agent/attribute_processing.rb +62 -0
  10. data/lib/new_relic/agent/commands/xray_session_collection.rb +4 -1
  11. data/lib/new_relic/agent/configuration/default_source.rb +284 -30
  12. data/lib/new_relic/agent/configuration/high_security_source.rb +0 -8
  13. data/lib/new_relic/agent/configuration/manager.rb +1 -1
  14. data/lib/new_relic/agent/configuration/server_source.rb +86 -31
  15. data/lib/new_relic/agent/configuration/yaml_source.rb +1 -1
  16. data/lib/new_relic/agent/cross_app_monitor.rb +8 -13
  17. data/lib/new_relic/agent/cross_app_tracing.rb +15 -15
  18. data/lib/new_relic/agent/custom_event_aggregator.rb +6 -2
  19. data/lib/new_relic/agent/database.rb +15 -2
  20. data/lib/new_relic/agent/datastores.rb +52 -38
  21. data/lib/new_relic/agent/datastores/metric_helper.rb +2 -1
  22. data/lib/new_relic/agent/encoding_normalizer.rb +82 -0
  23. data/lib/new_relic/agent/error_collector.rb +125 -169
  24. data/lib/new_relic/agent/hash_extensions.rb +26 -0
  25. data/lib/new_relic/agent/http_clients/excon_wrappers.rb +13 -11
  26. data/lib/new_relic/agent/http_clients/uri_util.rb +9 -0
  27. data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +1 -3
  28. data/lib/new_relic/agent/instrumentation/action_view_subscriber.rb +1 -1
  29. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +1 -1
  30. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +12 -5
  31. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +6 -7
  32. data/lib/new_relic/agent/instrumentation/curb.rb +6 -6
  33. data/lib/new_relic/agent/instrumentation/excon/middleware.rb +4 -4
  34. data/lib/new_relic/agent/instrumentation/grape.rb +4 -3
  35. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +6 -3
  36. data/lib/new_relic/agent/instrumentation/rails/errors.rb +9 -3
  37. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +6 -1
  38. data/lib/new_relic/agent/instrumentation/rails3/errors.rb +9 -7
  39. data/lib/new_relic/agent/instrumentation/rails4/errors.rb +8 -6
  40. data/lib/new_relic/agent/instrumentation/resque.rb +2 -3
  41. data/lib/new_relic/agent/instrumentation/sidekiq.rb +3 -3
  42. data/lib/new_relic/agent/instrumentation/typhoeus.rb +2 -2
  43. data/lib/new_relic/agent/javascript_instrumentor.rb +24 -16
  44. data/lib/new_relic/agent/parameter_filtering.rb +8 -1
  45. data/lib/new_relic/agent/samplers/delayed_job_sampler.rb +2 -2
  46. data/lib/new_relic/agent/sql_sampler.rb +1 -0
  47. data/lib/new_relic/agent/stats.rb +0 -4
  48. data/lib/new_relic/agent/stats_engine/metric_stats.rb +5 -3
  49. data/lib/new_relic/agent/stats_engine/stats_hash.rb +4 -0
  50. data/lib/new_relic/agent/supported_versions.rb +2 -2
  51. data/lib/new_relic/agent/traced_method_stack.rb +3 -3
  52. data/lib/new_relic/agent/transaction.rb +141 -118
  53. data/lib/new_relic/agent/transaction/attributes.rb +161 -0
  54. data/lib/new_relic/agent/transaction/developer_mode_sample_buffer.rb +4 -4
  55. data/lib/new_relic/agent/transaction/trace.rb +150 -0
  56. data/lib/new_relic/agent/transaction/trace_node.rb +190 -0
  57. data/lib/new_relic/agent/transaction/transaction_sample_buffer.rb +2 -2
  58. data/lib/new_relic/agent/transaction_event_aggregator.rb +23 -7
  59. data/lib/new_relic/agent/transaction_sample_builder.rb +37 -62
  60. data/lib/new_relic/agent/transaction_sampler.rb +29 -66
  61. data/lib/new_relic/cli/commands/install.rb +2 -2
  62. data/lib/new_relic/coerce.rb +15 -28
  63. data/lib/new_relic/json_wrapper.rb +14 -73
  64. data/lib/new_relic/noticed_error.rb +81 -5
  65. data/lib/new_relic/rack/browser_monitoring.rb +14 -19
  66. data/lib/new_relic/rack/developer_mode.rb +68 -14
  67. data/lib/new_relic/rack/developer_mode/segment_summary.rb +56 -0
  68. data/lib/new_relic/version.rb +2 -2
  69. data/newrelic.yml +19 -196
  70. data/test/agent_helper.rb +42 -36
  71. data/test/config/newrelic.yml +0 -1
  72. data/test/environments/rails40/Gemfile +1 -1
  73. data/test/environments/rails41/Gemfile +1 -1
  74. data/test/environments/rails42/Gemfile +1 -1
  75. data/test/fixtures/cross_agent_tests/attribute_configuration.json +35 -0
  76. data/test/fixtures/cross_agent_tests/sql_obfuscation/README.md +19 -12
  77. data/test/fixtures/cross_agent_tests/sql_obfuscation/sql_obfuscation.json +365 -0
  78. data/test/multiverse/lib/multiverse/suite.rb +5 -1
  79. data/test/multiverse/suites/active_record/active_record_test.rb +8 -8
  80. data/test/multiverse/suites/agent_only/agent_attributes_test.rb +145 -0
  81. data/test/multiverse/suites/agent_only/cross_application_tracing_test.rb +8 -0
  82. data/test/multiverse/suites/agent_only/custom_queue_time_test.rb +5 -1
  83. data/test/multiverse/suites/agent_only/encoding_handling_test.rb +6 -6
  84. data/test/multiverse/suites/agent_only/marshaling_test.rb +1 -1
  85. data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +2 -3
  86. data/test/multiverse/suites/agent_only/synthetics_test.rb +3 -3
  87. data/test/multiverse/suites/agent_only/testing_app.rb +4 -0
  88. data/test/multiverse/suites/agent_only/thread_profiling_test.rb +1 -1
  89. data/test/multiverse/suites/agent_only/utilization_data_collection_test.rb +9 -7
  90. data/test/multiverse/suites/curb/Envfile +5 -6
  91. data/test/multiverse/suites/curb/curb_test.rb +4 -5
  92. data/test/multiverse/suites/datamapper/datamapper_test.rb +2 -2
  93. data/test/multiverse/suites/excon/Envfile +11 -4
  94. data/test/multiverse/suites/excon/excon_test.rb +5 -5
  95. data/test/multiverse/suites/grape/config/newrelic.yml +1 -0
  96. data/test/multiverse/suites/grape/grape_test.rb +76 -12
  97. data/test/multiverse/suites/grape/grape_test_api.rb +16 -0
  98. data/test/multiverse/suites/high_security/config/newrelic.yml +43 -3
  99. data/test/multiverse/suites/high_security/high_security_test.rb +165 -9
  100. data/test/multiverse/suites/httpclient/Envfile +5 -1
  101. data/test/multiverse/suites/httpclient/httpclient_test.rb +2 -2
  102. data/test/multiverse/suites/memcached/Envfile +1 -1
  103. data/test/multiverse/suites/mongo/Envfile +8 -1
  104. data/test/multiverse/suites/mongo/helpers/mongo_operation_tests.rb +29 -29
  105. data/test/multiverse/suites/mongo/mongo_unsupported_version_test.rb +43 -8
  106. data/test/multiverse/suites/rack/rack_parameter_filtering_test.rb +13 -3
  107. data/test/multiverse/suites/rails/Envfile +3 -3
  108. data/test/multiverse/suites/rails/error_tracing_test.rb +52 -31
  109. data/test/multiverse/suites/rails/gc_instrumentation_test.rb +1 -1
  110. data/test/multiverse/suites/rails/ignore_test.rb +1 -1
  111. data/test/multiverse/suites/rails/parameter_capture_test.rb +108 -40
  112. data/test/multiverse/suites/rails/request_statistics_test.rb +10 -4
  113. data/test/multiverse/suites/rails/view_instrumentation_test.rb +24 -24
  114. data/test/multiverse/suites/resque/instrumentation_test.rb +46 -12
  115. data/test/multiverse/suites/sequel/sequel_extension_test.rb +8 -8
  116. data/test/multiverse/suites/sequel/sequel_helpers.rb +11 -11
  117. data/test/multiverse/suites/sequel/sequel_plugin_test.rb +11 -11
  118. data/test/multiverse/suites/sidekiq/Envfile +1 -4
  119. data/test/multiverse/suites/sidekiq/after_suite.rb +9 -0
  120. data/test/multiverse/suites/sidekiq/sidekiq_instrumentation_test.rb +49 -16
  121. data/test/multiverse/suites/sidekiq/test_worker.rb +1 -2
  122. data/test/multiverse/suites/sinatra/Envfile +1 -1
  123. data/test/multiverse/suites/sinatra/config/newrelic.yml +1 -0
  124. data/test/multiverse/suites/sinatra/sinatra_classic_test.rb +0 -4
  125. data/test/multiverse/suites/sinatra/sinatra_modular_test.rb +0 -4
  126. data/test/multiverse/suites/sinatra/sinatra_parameter_capture_test.rb +65 -0
  127. data/test/multiverse/suites/sinatra/sinatra_test_cases.rb +0 -11
  128. data/test/multiverse/suites/typhoeus/Envfile +8 -2
  129. data/test/multiverse/suites/typhoeus/typhoeus_test.rb +4 -4
  130. data/test/new_relic/agent/agent/connect_test.rb +13 -9
  131. data/test/new_relic/agent/agent_test.rb +34 -24
  132. data/test/new_relic/agent/attribute_filter_test.rb +218 -0
  133. data/test/new_relic/agent/attribute_processing_test.rb +160 -0
  134. data/test/new_relic/agent/configuration/default_source_test.rb +88 -0
  135. data/test/new_relic/agent/configuration/manager_test.rb +3 -4
  136. data/test/new_relic/agent/configuration/orphan_configuration_test.rb +3 -1
  137. data/test/new_relic/agent/configuration/server_source_test.rb +39 -0
  138. data/test/new_relic/agent/cross_app_monitor_test.rb +6 -30
  139. data/test/new_relic/agent/cross_app_tracing_test.rb +12 -12
  140. data/test/new_relic/agent/database/sql_obfuscation_test.rb +39 -65
  141. data/test/new_relic/agent/datastores/metric_helper_test.rb +36 -0
  142. data/test/new_relic/agent/encoding_normalizer_test.rb +66 -0
  143. data/test/new_relic/agent/error_collector_test.rb +181 -34
  144. data/test/new_relic/agent/hash_extensions_test.rb +34 -0
  145. data/test/new_relic/agent/instrumentation/action_controller_subscriber_test.rb +20 -23
  146. data/test/new_relic/agent/instrumentation/action_view_subscriber_test.rb +12 -12
  147. data/test/new_relic/agent/instrumentation/active_record_subscriber_test.rb +5 -5
  148. data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +4 -4
  149. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +21 -11
  150. data/test/new_relic/agent/javascript_instrumentor_test.rb +69 -45
  151. data/test/new_relic/agent/pipe_service_test.rb +2 -2
  152. data/test/new_relic/agent/stats_engine/gc_profiler_test.rb +1 -1
  153. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +8 -7
  154. data/test/new_relic/agent/stats_engine/stats_hash_test.rb +2 -2
  155. data/test/new_relic/agent/threading/backtrace_node_test.rb +2 -2
  156. data/test/new_relic/agent/transaction/attributes_test.rb +276 -0
  157. data/test/new_relic/agent/transaction/developer_mode_sample_buffer_test.rb +10 -10
  158. data/test/new_relic/agent/transaction/trace_node_test.rb +361 -0
  159. data/test/new_relic/agent/transaction/trace_test.rb +394 -0
  160. data/test/new_relic/agent/transaction/xray_sample_buffer_test.rb +1 -1
  161. data/test/new_relic/agent/transaction_event_aggregator_test.rb +127 -57
  162. data/test/new_relic/agent/transaction_sample_builder_test.rb +70 -78
  163. data/test/new_relic/agent/transaction_sampler_test.rb +76 -185
  164. data/test/new_relic/agent/transaction_test.rb +283 -135
  165. data/test/new_relic/agent_test.rb +27 -12
  166. data/test/new_relic/cli/commands/install_test.rb +27 -0
  167. data/test/new_relic/coerce_test.rb +0 -59
  168. data/test/new_relic/data_container_tests.rb +5 -5
  169. data/test/new_relic/fake_collector.rb +27 -9
  170. data/test/new_relic/filtering_test_app.rb +2 -1
  171. data/test/new_relic/http_client_test_cases.rb +16 -16
  172. data/test/new_relic/json_wrapper_test.rb +0 -54
  173. data/test/new_relic/marshalling_test_cases.rb +1 -0
  174. data/test/new_relic/multiverse_helpers.rb +144 -0
  175. data/test/new_relic/noticed_error_test.rb +112 -9
  176. data/test/new_relic/rack/browser_monitoring_test.rb +12 -7
  177. data/test/new_relic/{transaction_analysis → rack/developer_mode}/segment_summary_test.rb +5 -4
  178. data/test/new_relic/rack/developer_mode_test.rb +17 -3
  179. data/test/new_relic/rack/error_collector_test.rb +1 -1
  180. data/test/performance/lib/performance/instrumentation/stackprof.rb +1 -1
  181. data/test/performance/script/runner +2 -2
  182. data/test/performance/suites/active_record.rb +3 -3
  183. data/test/performance/suites/agent_attributes.rb +62 -0
  184. data/test/performance/suites/rack_middleware.rb +78 -28
  185. data/test/performance/suites/transaction_tracing.rb +35 -0
  186. data/test/test_helper.rb +9 -1
  187. data/ui/helpers/developer_mode_helper.rb +16 -23
  188. data/ui/views/newrelic/_sample.rhtml +3 -3
  189. data/ui/views/newrelic/_segment.rhtml +1 -1
  190. data/ui/views/newrelic/_show_sample_summary.rhtml +1 -1
  191. data/ui/views/newrelic/show_sample.rhtml +5 -4
  192. metadata +23 -80
  193. data/lib/new_relic/agent/transaction/force_persist_sample_buffer.rb +0 -25
  194. data/lib/new_relic/transaction_analysis.rb +0 -80
  195. data/lib/new_relic/transaction_analysis/segment_summary.rb +0 -53
  196. data/lib/new_relic/transaction_sample.rb +0 -207
  197. data/lib/new_relic/transaction_sample/composite_segment.rb +0 -31
  198. data/lib/new_relic/transaction_sample/fake_segment.rb +0 -13
  199. data/lib/new_relic/transaction_sample/segment.rb +0 -197
  200. data/lib/new_relic/transaction_sample/summary_segment.rb +0 -25
  201. data/lib/new_relic/url_rule.rb +0 -18
  202. data/test/fixtures/cross_agent_tests/sql_obfuscation/back_quoted_identifiers.mysql.obfuscated +0 -1
  203. data/test/fixtures/cross_agent_tests/sql_obfuscation/back_quoted_identifiers.mysql.sql +0 -1
  204. data/test/fixtures/cross_agent_tests/sql_obfuscation/comment_delimiters_in_strings.obfuscated +0 -1
  205. data/test/fixtures/cross_agent_tests/sql_obfuscation/comment_delimiters_in_strings.sql +0 -1
  206. data/test/fixtures/cross_agent_tests/sql_obfuscation/double_quoted_identifiers.postgres.obfuscated +0 -1
  207. data/test/fixtures/cross_agent_tests/sql_obfuscation/double_quoted_identifiers.postgres.sql +0 -1
  208. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_line_comment_in_string.obfuscated +0 -2
  209. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_line_comment_in_string.sql +0 -2
  210. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_cstyle.obfuscated +0 -1
  211. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_cstyle.sql +0 -1
  212. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_doubledash.obfuscated +0 -2
  213. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_doubledash.sql +0 -2
  214. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_hash.obfuscated +0 -1
  215. data/test/fixtures/cross_agent_tests/sql_obfuscation/end_of_query_comment_hash.sql +0 -1
  216. data/test/fixtures/cross_agent_tests/sql_obfuscation/escape_string_constants.postgres.obfuscated +0 -1
  217. data/test/fixtures/cross_agent_tests/sql_obfuscation/escape_string_constants.postgres.sql +0 -4
  218. data/test/fixtures/cross_agent_tests/sql_obfuscation/malformed/unterminated_double_quoted_string.mysql.sql +0 -1
  219. data/test/fixtures/cross_agent_tests/sql_obfuscation/malformed/unterminated_single_quoted_string.sql +0 -1
  220. data/test/fixtures/cross_agent_tests/sql_obfuscation/multiple_literal_types.mysql.obfuscated +0 -1
  221. data/test/fixtures/cross_agent_tests/sql_obfuscation/multiple_literal_types.mysql.sql +0 -1
  222. data/test/fixtures/cross_agent_tests/sql_obfuscation/numbers_in_identifiers.obfuscated +0 -1
  223. data/test/fixtures/cross_agent_tests/sql_obfuscation/numbers_in_identifiers.sql +0 -1
  224. data/test/fixtures/cross_agent_tests/sql_obfuscation/numeric_literals.obfuscated +0 -1
  225. data/test/fixtures/cross_agent_tests/sql_obfuscation/numeric_literals.sql +0 -1
  226. data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/README.md +0 -4
  227. data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/end_of_line_comments_with_quotes.obfuscated +0 -1
  228. data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/end_of_line_comments_with_quotes.sql +0 -2
  229. data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/mixed_comments_and_quotes.obfuscated +0 -1
  230. data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/mixed_comments_and_quotes.sql +0 -2
  231. data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/mixed_quotes_comments_and_newlines.obfuscated +0 -1
  232. data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/mixed_quotes_comments_and_newlines.sql +0 -4
  233. data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/mixed_quotes_end_of_line_comments.obfuscated +0 -1
  234. data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/mixed_quotes_end_of_line_comments.sql +0 -3
  235. data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/quote_delimiters_in_comments.obfuscated +0 -1
  236. data/test/fixtures/cross_agent_tests/sql_obfuscation/pathological/quote_delimiters_in_comments.sql +0 -1
  237. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_double_quoted.mysql.obfuscated +0 -1
  238. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_double_quoted.mysql.sql +0 -1
  239. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_single_quoted.obfuscated +0 -1
  240. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_single_quoted.sql +0 -1
  241. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_backslash_and_twin_single_quotes.obfuscated +0 -1
  242. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_backslash_and_twin_single_quotes.sql +0 -4
  243. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_double_quote.obfuscated +0 -1
  244. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_double_quote.sql +0 -1
  245. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_newline.obfuscated +0 -1
  246. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_newline.sql +0 -2
  247. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_single_quote.mysql.obfuscated +0 -1
  248. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_embedded_single_quote.mysql.sql +0 -1
  249. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_escaped_quotes.mysql.obfuscated +0 -1
  250. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_escaped_quotes.mysql.sql +0 -1
  251. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_backslash.obfuscated +0 -1
  252. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_backslash.sql +0 -4
  253. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_backslash.mysql.obfuscated +0 -1
  254. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_backslash.mysql.sql +0 -1
  255. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_backslash_single_quoted.obfuscated +0 -1
  256. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_backslash_single_quoted.sql +0 -1
  257. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_quote.obfuscated +0 -1
  258. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_trailing_escaped_quote.sql +0 -1
  259. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_twin_single_quotes.obfuscated +0 -1
  260. data/test/fixtures/cross_agent_tests/sql_obfuscation/string_with_twin_single_quotes.sql +0 -1
  261. data/test/new_relic/agent/error_collector/notice_error_test.rb +0 -261
  262. data/test/new_relic/agent/transaction/force_persist_sample_buffer_test.rb +0 -52
  263. data/test/new_relic/transaction_analysis_test.rb +0 -125
  264. data/test/new_relic/transaction_sample/composite_segment_test.rb +0 -38
  265. data/test/new_relic/transaction_sample/fake_segment_test.rb +0 -18
  266. data/test/new_relic/transaction_sample/segment_test.rb +0 -361
  267. data/test/new_relic/transaction_sample/summary_segment_test.rb +0 -34
  268. data/test/new_relic/transaction_sample_subtest_test.rb +0 -41
  269. data/test/new_relic/transaction_sample_test.rb +0 -361
@@ -46,7 +46,8 @@ module NewRelic
46
46
 
47
47
  def self.metrics_for(product, operation, collection = nil)
48
48
  if overrides = overridden_operation_and_collection
49
- operation, collection = overrides
49
+ operation = overrides[0] || operation
50
+ collection = overrides[1] || collection
50
51
  end
51
52
 
52
53
  suffix = all_suffix
@@ -0,0 +1,82 @@
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
+ # This module was extracted from NewRelic::JSONWrapper
6
+
7
+ module NewRelic
8
+ module Agent
9
+ module EncodingNormalizer
10
+ def self.normalize_string(raw_string)
11
+ @normalizer ||= choose_normalizer
12
+ @normalizer.normalize(raw_string)
13
+ end
14
+
15
+ def self.normalize_object(object)
16
+ case object
17
+ when String
18
+ normalize_string(object)
19
+ when Symbol
20
+ normalize_string(object.to_s)
21
+ when Array
22
+ return object if object.empty?
23
+ object.map { |x| normalize_object(x) }
24
+ when Hash
25
+ return object if object.empty?
26
+ hash = {}
27
+ object.each_pair do |k, v|
28
+ k = normalize_string(k) if k.is_a?(String)
29
+ k = normalize_string(k.to_s) if k.is_a?(Symbol)
30
+ hash[k] = normalize_object(v)
31
+ end
32
+ hash
33
+ else
34
+ object
35
+ end
36
+ end
37
+
38
+ def self.choose_normalizer
39
+ if NewRelic::LanguageSupport.supports_string_encodings?
40
+ EncodingNormalizer
41
+ else
42
+ IconvNormalizer
43
+ end
44
+ end
45
+
46
+ module EncodingNormalizer
47
+ def self.normalize(raw_string)
48
+ encoding = raw_string.encoding
49
+ if (encoding == Encoding::UTF_8 || encoding == Encoding::ISO_8859_1) && raw_string.valid_encoding?
50
+ return raw_string
51
+ end
52
+
53
+ # If the encoding is not valid, or it's ASCII-8BIT, we know conversion to
54
+ # UTF-8 is likely to fail, so treat it as ISO-8859-1 (byte-preserving).
55
+ normalized = raw_string.dup
56
+ if encoding == Encoding::ASCII_8BIT || !raw_string.valid_encoding?
57
+ normalized.force_encoding(Encoding::ISO_8859_1)
58
+ else
59
+ # Encoding is valid and non-binary, so it might be cleanly convertible
60
+ # to UTF-8. Give it a try and fall back to ISO-8859-1 if it fails.
61
+ begin
62
+ normalized.encode!(Encoding::UTF_8)
63
+ rescue
64
+ normalized.force_encoding(Encoding::ISO_8859_1)
65
+ end
66
+ end
67
+ normalized
68
+ end
69
+ end
70
+
71
+ module IconvNormalizer
72
+ def self.normalize(raw_string)
73
+ if @iconv.nil?
74
+ require 'iconv'
75
+ @iconv = Iconv.new('utf-8', 'iso-8859-1')
76
+ end
77
+ @iconv.iconv(raw_string)
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -93,208 +93,165 @@ module NewRelic
93
93
  end
94
94
  end
95
95
 
96
- # This module was extracted from the notice_error method - it is
97
- # internally tested and can be refactored without major issues.
98
- module NoticeError
99
- # Checks the provided error against the error filter, if there
100
- # is an error filter
101
- def filtered_by_error_filter?(error)
102
- respond_to?(:ignore_filter_proc) && !ignore_filter_proc(error)
103
- end
104
-
105
- # Checks the array of error names and the error filter against
106
- # the provided error
107
- def filtered_error?(error)
108
- @ignore[error.class.name] || filtered_by_error_filter?(error)
109
- end
110
-
111
- # an error is ignored if it is nil or if it is filtered
112
- def error_is_ignored?(error)
113
- error && filtered_error?(error)
114
- rescue => e
115
- NewRelic::Agent.logger.error("Error '#{error}' will NOT be ignored. Exception '#{e}' while determining whether to ignore or not.", e)
116
- false
117
- end
118
-
119
- def seen?(txn, exception)
120
- error_ids = txn.nil? ? [] : txn.noticed_error_ids
121
- error_ids.include?(exception.object_id)
122
- end
123
-
124
- def tag_as_seen(state, exception)
125
- txn = state.current_transaction
126
- txn.noticed_error_ids << exception.object_id if txn
127
- end
128
-
129
- def blamed_metric_name(txn, options)
130
- if options[:metric] && options[:metric] != ::NewRelic::Agent::UNKNOWN_METRIC
131
- "Errors/#{options[:metric]}"
132
- else
133
- "Errors/#{txn.best_name}" if txn
134
- end
135
- end
136
-
137
- def aggregated_metric_names(txn)
138
- metric_names = ["Errors/all"]
139
- return metric_names unless txn
96
+ # Checks the provided error against the error filter, if there
97
+ # is an error filter
98
+ def filtered_by_error_filter?(error)
99
+ respond_to?(:ignore_filter_proc) && !ignore_filter_proc(error)
100
+ end
140
101
 
141
- if txn.recording_web_transaction?
142
- metric_names << "Errors/allWeb"
143
- else
144
- metric_names << "Errors/allOther"
145
- end
102
+ # Checks the array of error names and the error filter against
103
+ # the provided error
104
+ def filtered_error?(error)
105
+ @ignore[error.class.name] || filtered_by_error_filter?(error)
106
+ end
146
107
 
147
- metric_names
148
- end
108
+ # an error is ignored if it is nil or if it is filtered
109
+ def error_is_ignored?(error)
110
+ error && filtered_error?(error)
111
+ rescue => e
112
+ NewRelic::Agent.logger.error("Error '#{error}' will NOT be ignored. Exception '#{e}' while determining whether to ignore or not.", e)
113
+ false
114
+ end
149
115
 
150
- # Increments a statistic that tracks total error rate
151
- def increment_error_count!(state, exception, options={})
152
- txn = state.current_transaction
116
+ def seen?(txn, exception)
117
+ error_ids = txn.nil? ? [] : txn.noticed_error_ids
118
+ error_ids.include?(exception.object_id)
119
+ end
153
120
 
154
- metric_names = aggregated_metric_names(txn)
155
- blamed_metric = blamed_metric_name(txn, options)
156
- metric_names << blamed_metric if blamed_metric
121
+ def tag_as_seen(state, exception)
122
+ txn = state.current_transaction
123
+ txn.noticed_error_ids << exception.object_id if txn
124
+ end
157
125
 
158
- stats_engine = NewRelic::Agent.agent.stats_engine
159
- stats_engine.record_unscoped_metrics(state, metric_names) do |stats|
160
- stats.increment_count
161
- end
126
+ def blamed_metric_name(txn, options)
127
+ if options[:metric] && options[:metric] != ::NewRelic::Agent::UNKNOWN_METRIC
128
+ "Errors/#{options[:metric]}"
129
+ else
130
+ "Errors/#{txn.best_name}" if txn
162
131
  end
132
+ end
163
133
 
164
- def skip_notice_error?(state, exception)
165
- disabled? ||
166
- error_is_ignored?(exception) ||
167
- exception.nil? ||
168
- seen?(state.current_transaction, exception)
169
- end
134
+ def aggregated_metric_names(txn)
135
+ metric_names = ["Errors/all"]
136
+ return metric_names unless txn
170
137
 
171
- # acts just like Hash#fetch, but deletes the key from the hash
172
- def fetch_from_options(options, key, default=nil)
173
- options.delete(key) || default
138
+ if txn.recording_web_transaction?
139
+ metric_names << "Errors/allWeb"
140
+ else
141
+ metric_names << "Errors/allOther"
174
142
  end
175
143
 
176
- # returns some basic option defaults pulled from the provided
177
- # options hash
178
- def uri_ref_and_root(options)
179
- {
180
- :request_uri => fetch_from_options(options, :uri, ''),
181
- :request_referer => fetch_from_options(options, :referer, ''),
182
- :rails_root => NewRelic::Control.instance.root
183
- }
184
- end
144
+ metric_names
145
+ end
185
146
 
186
- # If anything else is left over, we treat it like a custom param
187
- def custom_params_from_opts(options)
188
- # If anything else is left over, treat it like a custom param:
189
- if Agent.config[:'error_collector.capture_attributes']
190
- fetch_from_options(options, :custom_params, {}).merge(options)
191
- else
192
- {}
193
- end
194
- end
147
+ # Increments a statistic that tracks total error rate
148
+ def increment_error_count!(state, exception, options={})
149
+ txn = state.current_transaction
195
150
 
196
- # takes the request parameters out of the options hash, and
197
- # returns them if we are capturing parameters, otherwise
198
- # returns nil
199
- def request_params_from_opts(options)
200
- value = options.delete(:request_params)
201
- if Agent.config[:capture_params]
202
- value
203
- else
204
- nil
205
- end
206
- end
151
+ metric_names = aggregated_metric_names(txn)
152
+ blamed_metric = blamed_metric_name(txn, options)
153
+ metric_names << blamed_metric if blamed_metric
207
154
 
208
- # normalizes the request and custom parameters before attaching
209
- # them to the error. See NewRelic::CollectionHelper#normalize_params
210
- def normalized_request_and_custom_params(options)
211
- {
212
- :request_params => normalize_params(request_params_from_opts(options)),
213
- :custom_params => normalize_params(custom_params_from_opts(options))
214
- }
215
- end
216
-
217
- # Merges together many of the options into something that can
218
- # actually be attached to the error
219
- def error_params_from_options(options)
220
- uri_ref_and_root(options).merge(normalized_request_and_custom_params(options))
155
+ stats_engine = NewRelic::Agent.agent.stats_engine
156
+ stats_engine.record_unscoped_metrics(state, metric_names) do |stats|
157
+ stats.increment_count
221
158
  end
159
+ end
222
160
 
223
- # calls a method on an object, if it responds to it - used for
224
- # detection and soft fail-safe. Returns nil if the method does
225
- # not exist
226
- def sense_method(object, method)
227
- object.send(method) if object.respond_to?(method)
228
- end
161
+ def skip_notice_error?(state, exception)
162
+ disabled? ||
163
+ error_is_ignored?(exception) ||
164
+ exception.nil? ||
165
+ seen?(state.current_transaction, exception)
166
+ end
229
167
 
230
- # extracts a stack trace from the exception for debugging purposes
231
- def extract_stack_trace(exception)
232
- actual_exception = sense_method(exception, 'original_exception') || exception
233
- sense_method(actual_exception, 'backtrace') || '<no stack trace>'
234
- end
168
+ # calls a method on an object, if it responds to it - used for
169
+ # detection and soft fail-safe. Returns nil if the method does
170
+ # not exist
171
+ def sense_method(object, method)
172
+ object.send(method) if object.respond_to?(method)
173
+ end
235
174
 
236
- # extracts a bunch of information from the exception to include
237
- # in the noticed error - some may or may not be available, but
238
- # we try to include all of it
239
- def exception_info(exception)
240
- {
241
- :file_name => sense_method(exception, 'file_name'),
242
- :line_number => sense_method(exception, 'line_number'),
243
- :stack_trace => extract_stack_trace(exception)
244
- }
245
- end
175
+ # extracts a stack trace from the exception for debugging purposes
176
+ def extract_stack_trace(exception)
177
+ actual_exception = sense_method(exception, 'original_exception') || exception
178
+ sense_method(actual_exception, 'backtrace') || '<no stack trace>'
179
+ end
246
180
 
247
- # checks the size of the error queue to make sure we are under
248
- # the maximum limit, and logs a warning if we are over the limit.
249
- def over_queue_limit?(message)
250
- over_limit = (@errors.reject{|err| err.is_internal}.length >= MAX_ERROR_QUEUE_LENGTH)
251
- ::NewRelic::Agent.logger.warn("The error reporting queue has reached #{MAX_ERROR_QUEUE_LENGTH}. The error detail for this and subsequent errors will not be transmitted to New Relic until the queued errors have been sent: #{message}") if over_limit
252
- over_limit
253
- end
181
+ # checks the size of the error queue to make sure we are under
182
+ # the maximum limit, and logs a warning if we are over the limit.
183
+ def over_queue_limit?(message)
184
+ over_limit = (@errors.reject{|err| err.is_internal}.length >= MAX_ERROR_QUEUE_LENGTH)
185
+ ::NewRelic::Agent.logger.warn("The error reporting queue has reached #{MAX_ERROR_QUEUE_LENGTH}. The error detail for this and subsequent errors will not be transmitted to New Relic until the queued errors have been sent: #{message}") if over_limit
186
+ over_limit
187
+ end
254
188
 
255
- # Synchronizes adding an error to the error queue, and checks if
256
- # the error queue is too long - if so, we drop the error on the
257
- # floor after logging a warning.
258
- def add_to_error_queue(noticed_error)
259
- @lock.synchronize do
260
- if !over_queue_limit?(noticed_error.message) && !@errors.include?(noticed_error)
261
- @errors << noticed_error
262
- end
189
+ # Synchronizes adding an error to the error queue, and checks if
190
+ # the error queue is too long - if so, we drop the error on the
191
+ # floor after logging a warning.
192
+ def add_to_error_queue(noticed_error)
193
+ @lock.synchronize do
194
+ if !over_queue_limit?(noticed_error.message) && !@errors.include?(noticed_error)
195
+ @errors << noticed_error
263
196
  end
264
197
  end
265
198
  end
266
199
 
267
- include NoticeError
268
-
200
+ # See NewRelic::Agent.notice_error for options and commentary
269
201
 
270
- # Notice the error with the given available options:
271
- #
272
- # * <tt>:uri</tt> => The request path, minus any request params or query string.
273
- # * <tt>:referer</tt> => The URI of the referer
274
- # * <tt>:metric</tt> => The metric name associated with the transaction
275
- # * <tt>:request_params</tt> => Request parameters, already filtered if necessary
276
- # * <tt>:custom_params</tt> => Custom parameters
277
- #
278
- # If anything is left over, it's added to custom params
279
- # If exception is nil, the error count is bumped and no traced error is recorded
280
202
  def notice_error(exception, options={}) #THREAD_LOCAL_ACCESS
281
203
  state = ::NewRelic::Agent::TransactionState.tl_get
282
204
 
283
205
  return if skip_notice_error?(state, exception)
284
- tag_as_seen(state, exception)
285
206
 
207
+ tag_as_seen(state, exception)
286
208
  increment_error_count!(state, exception, options)
287
- NewRelic::Agent.instance.events.notify(:notice_error, exception, options)
288
-
289
- action_path = fetch_from_options(options, :metric, "")
290
- exception_options = error_params_from_options(options).merge(exception_info(exception))
291
- add_to_error_queue(NewRelic::NoticedError.new(action_path, exception_options, exception))
209
+ add_to_error_queue(create_noticed_error(exception, options))
292
210
 
293
211
  exception
294
212
  rescue => e
295
213
  ::NewRelic::Agent.logger.warn("Failure when capturing error '#{exception}':", e)
296
214
  end
297
215
 
216
+ EMPTY_STRING = ''.freeze
217
+
218
+ def create_noticed_error(exception, options)
219
+ error_metric = options.delete(:metric) || EMPTY_STRING
220
+
221
+ noticed_error = NewRelic::NoticedError.new(error_metric, exception)
222
+ noticed_error.request_uri = options.delete(:uri) || EMPTY_STRING
223
+ noticed_error.attributes = options.delete(:attributes)
224
+
225
+ noticed_error.file_name = sense_method(exception, :file_name)
226
+ noticed_error.line_number = sense_method(exception, :line_number)
227
+ noticed_error.stack_trace = extract_stack_trace(exception)
228
+
229
+ handle_deprecated_options(options)
230
+
231
+ noticed_error.attributes_from_notice_error = options.delete(:custom_params) || {}
232
+
233
+ # Any options that are passed to notice_error which aren't known keys
234
+ # get treated as custom attributes, so merge them into that hash.
235
+ noticed_error.attributes_from_notice_error.merge!(options)
236
+
237
+ noticed_error
238
+ end
239
+
240
+ DEPRECATED_OPTIONS_MSG = "Passing %s to notice_error is no longer supported. Set values on the enclosing transaction or record them as custom attributes instead.".freeze
241
+ DEPRECATED_OPTIONS = [:request_params, :request, :referer].freeze
242
+
243
+ # Old options no longer used by notice_error can still be passed. If they
244
+ # are, they shouldn't get merged into custom attributes. Delete and
245
+ # warn callers so they can fix their calls to notice_error.
246
+ def handle_deprecated_options(options)
247
+ DEPRECATED_OPTIONS.each do |deprecated|
248
+ if options.include?(deprecated)
249
+ NewRelic::Agent.logger.warn(DEPRECATED_OPTIONS_MSG % deprecated)
250
+ options.delete(deprecated)
251
+ end
252
+ end
253
+ end
254
+
298
255
  # *Use sparingly for difficult to track bugs.*
299
256
  #
300
257
  # Track internal agent errors for communication back to New Relic.
@@ -315,9 +272,8 @@ module NewRelic
315
272
  return if @errors.any? { |err| err.exception_class_name == exception.class.name }
316
273
 
317
274
  trace = exception.backtrace || caller.dup
318
- noticed_error = NewRelic::NoticedError.new("NewRelic/AgentError",
319
- {:stack_trace => trace},
320
- exception)
275
+ noticed_error = NewRelic::NoticedError.new("NewRelic/AgentError", exception)
276
+ noticed_error.stack_trace = trace
321
277
  @errors << noticed_error
322
278
  end
323
279
  rescue => e
@@ -0,0 +1,26 @@
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 HashExtensions
8
+ module_function
9
+
10
+ # recurses through hashes and arrays and stringifies keys
11
+ def stringify_keys_in_object(object)
12
+ case object
13
+ when Hash
14
+ object.inject({}) do |memo, (k, v)|
15
+ memo[k.to_s] = stringify_keys_in_object(v)
16
+ memo
17
+ end
18
+ when Array
19
+ object.map {|o| stringify_keys_in_object(o)}
20
+ else
21
+ object
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end