dolores_rpm 3.2.0.6 → 3.3.4.fork

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/CHANGELOG +32 -6
  2. data/dolores_rpm.gemspec +15 -11
  3. data/lib/new_relic/agent/agent.rb +28 -14
  4. data/lib/new_relic/agent/beacon_configuration.rb +11 -0
  5. data/lib/new_relic/agent/browser_monitoring.rb +53 -13
  6. data/lib/new_relic/agent/database.rb +34 -14
  7. data/lib/new_relic/agent/error_collector.rb +1 -1
  8. data/lib/new_relic/agent/instrumentation/active_merchant.rb +3 -1
  9. data/lib/new_relic/agent/instrumentation/active_record.rb +137 -0
  10. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +24 -5
  11. data/lib/new_relic/agent/instrumentation/data_mapper.rb +4 -36
  12. data/lib/new_relic/agent/instrumentation/metric_frame.rb +24 -3
  13. data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +3 -2
  14. data/lib/new_relic/agent/instrumentation/queue_time.rb +1 -1
  15. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +88 -30
  16. data/lib/new_relic/agent/instrumentation/sinatra.rb +40 -20
  17. data/lib/new_relic/agent/samplers/memory_sampler.rb +5 -6
  18. data/lib/new_relic/agent/sql_sampler.rb +35 -16
  19. data/lib/new_relic/agent/stats_engine/gc_profiler.rb +123 -0
  20. data/lib/new_relic/agent/stats_engine/samplers.rb +1 -1
  21. data/lib/new_relic/agent/stats_engine/transactions.rb +2 -85
  22. data/lib/new_relic/agent/stats_engine.rb +1 -0
  23. data/lib/new_relic/agent/transaction_info.rb +74 -0
  24. data/lib/new_relic/agent/transaction_sample_builder.rb +17 -3
  25. data/lib/new_relic/agent/transaction_sampler.rb +86 -15
  26. data/lib/new_relic/agent/worker_loop.rb +1 -1
  27. data/lib/new_relic/agent.rb +15 -2
  28. data/lib/new_relic/collection_helper.rb +8 -6
  29. data/lib/new_relic/command.rb +1 -1
  30. data/lib/new_relic/commands/deployments.rb +1 -1
  31. data/lib/new_relic/control/configuration.rb +6 -2
  32. data/lib/new_relic/control/frameworks/merb.rb +1 -1
  33. data/lib/new_relic/control/frameworks/rails.rb +5 -5
  34. data/lib/new_relic/control/frameworks/rails3.rb +2 -2
  35. data/lib/new_relic/control/instance_methods.rb +3 -3
  36. data/lib/new_relic/control/instrumentation.rb +1 -1
  37. data/lib/new_relic/control/server_methods.rb +2 -2
  38. data/lib/new_relic/data_serialization.rb +10 -16
  39. data/lib/new_relic/delayed_job_injection.rb +6 -1
  40. data/lib/new_relic/language_support.rb +11 -7
  41. data/lib/new_relic/local_environment.rb +24 -10
  42. data/lib/new_relic/metric_spec.rb +7 -6
  43. data/lib/new_relic/noticed_error.rb +6 -1
  44. data/lib/new_relic/rack/browser_monitoring.rb +21 -13
  45. data/lib/new_relic/rack/developer_mode.rb +2 -2
  46. data/lib/new_relic/recipes.rb +8 -4
  47. data/lib/new_relic/stats.rb +0 -53
  48. data/lib/new_relic/transaction_sample/segment.rb +2 -0
  49. data/lib/new_relic/transaction_sample.rb +39 -23
  50. data/lib/new_relic/version.rb +3 -3
  51. data/test/active_record_fixtures.rb +3 -3
  52. data/test/fixtures/proc_cpuinfo.txt +575 -0
  53. data/test/new_relic/agent/agent/connect_test.rb +4 -11
  54. data/test/new_relic/agent/agent_test.rb +1 -0
  55. data/test/new_relic/agent/agent_test_controller_test.rb +20 -1
  56. data/test/new_relic/agent/beacon_configuration_test.rb +10 -7
  57. data/test/new_relic/agent/browser_monitoring_test.rb +90 -45
  58. data/test/new_relic/agent/database_test.rb +34 -47
  59. data/test/new_relic/agent/error_collector_test.rb +32 -15
  60. data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +56 -18
  61. data/test/new_relic/agent/instrumentation/controller_instrumentation_test.rb +0 -2
  62. data/test/new_relic/agent/instrumentation/metric_frame/pop_test.rb +0 -1
  63. data/test/new_relic/agent/instrumentation/net_instrumentation_test.rb +3 -3
  64. data/test/new_relic/agent/instrumentation/queue_time_test.rb +6 -11
  65. data/test/new_relic/agent/method_tracer/class_methods/add_method_tracer_test.rb +1 -1
  66. data/test/new_relic/agent/method_tracer_test.rb +2 -2
  67. data/test/new_relic/agent/rpm_agent_test.rb +1 -1
  68. data/test/new_relic/agent/sql_sampler_test.rb +48 -16
  69. data/test/new_relic/agent/stats_engine_test.rb +41 -6
  70. data/test/new_relic/agent/transaction_info_test.rb +13 -0
  71. data/test/new_relic/agent/transaction_sample_builder_test.rb +19 -3
  72. data/test/new_relic/agent/transaction_sampler_test.rb +49 -37
  73. data/test/new_relic/agent/worker_loop_test.rb +1 -1
  74. data/test/new_relic/agent_test.rb +12 -0
  75. data/test/new_relic/control/configuration_test.rb +12 -0
  76. data/test/new_relic/control_test.rb +2 -0
  77. data/test/new_relic/data_serialization_test.rb +12 -12
  78. data/test/new_relic/local_environment_test.rb +14 -1
  79. data/test/new_relic/metric_parser/metric_parser_test.rb +11 -0
  80. data/test/new_relic/rack/browser_monitoring_test.rb +81 -23
  81. data/test/new_relic/rack/developer_mode_test.rb +31 -0
  82. data/test/new_relic/stats_test.rb +0 -15
  83. data/test/new_relic/transaction_sample_test.rb +13 -0
  84. data/test/script/build_test_gem.sh +51 -0
  85. data/test/script/ci.sh +94 -0
  86. data/test/script/ci_bench.sh +52 -0
  87. data/test/test_helper.rb +1 -0
  88. data/vendor/gems/dependency_detection-0.0.1.build/lib/dependency_detection.rb +5 -0
  89. data/vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/metric_parser.rb +17 -4
  90. metadata +25 -19
  91. data/dolores_rpm-3.2.0.2.gem +0 -0
  92. data/dolores_rpm-3.2.0.5.gem +0 -0
  93. data/dolores_rpm-3.3.4.fork.gem +0 -0
  94. data/lib/new_relic/agent/instrumentation/rails/active_record_instrumentation.rb +0 -115
  95. data/lib/new_relic/agent/instrumentation/rails3/active_record_instrumentation.rb +0 -122
data/CHANGELOG CHANGED
@@ -1,11 +1,37 @@
1
- v3.2.0.6
2
- * Experimenting with adding 'ActiveRecord/all' to all DataMapper metrics to get accurate database slice on App Server Overview page
1
+ v3.3.4.fork
2
+ * Roll back to previous version of DataMapper instrumentation (current one does not work for our app)
3
3
 
4
- v3.2.0.5
5
- * Add DataMapper instrumentation for find/save/destroy with :push_scope => false (gets find to show up on database instrumentation)
4
+ v3.3.4
5
+ * Rails 3 view instrumentation
6
6
 
7
- v3.2.0.2
8
- * Roll back to previous version of DataMapper instrumentation (current one does not work for our app)
7
+ v3.3.3
8
+ * Improved Sinatra instrumentation
9
+ * Limit the number of nodes collected in long running transactions to prevent leaking memory
10
+
11
+ v3.3.2.1
12
+ * [SECURITY] fix for cookie handling by End User Monitoring instrumentation
13
+
14
+ v3.3.2
15
+ * deployments recipe change: truncate git SHAs to 7 characters
16
+ * Fixes for obfuscation of PostgreSQL and SQLite queries
17
+ * Fix for lost database connections when using a forking framework
18
+ * Workaround for RedHat kernel bug which prevented blocking reads of /proc fs
19
+ * Do not trap signals when handling exceptions
20
+
21
+ v3.3.1
22
+ * improved Ruby 1.8.6 support
23
+ * fix for issues with RAILS_ROOT deprecation warnings
24
+ * fixed incorrect 1.9 GC time reporting
25
+ * obfusction for Slow SQL queries respects transaction trace config
26
+ * fix for RUM instrumentation repoting bad timing info in some cases
27
+ * refactored ActiveRecord instrumentation, no longer requires Rails
28
+
29
+ v3.3.0
30
+ * fix for GC instrumentation when using Ruby 1.9
31
+ * new feature to correlate browser and server transaction traces
32
+ * new feature to trace slow sql statements
33
+ * fix to help cope with malformed rack responses
34
+ * do not try to instrument versions of ActiveMerchant that are too old
9
35
 
10
36
  v3.2.0.1
11
37
  * Updated LICENSE
data/dolores_rpm.gemspec CHANGED
@@ -5,14 +5,14 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "dolores_rpm"
8
- s.version = "3.2.0.6"
8
+ s.version = "3.3.4.fork"
9
9
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Bill Kayser", "Jon Guymon", "Justin George", "Darin Swanson"]
12
- s.date = "2012-05-10"
12
+ s.date = "2012-04-27"
13
13
  s.description = "New Relic is a performance management system, developed by New Relic,\nInc (http://www.newrelic.com). This is a fork that uses an older version\nof the DataMapper instrumentation. Newer versions did not work for us.\n"
14
14
  s.email = "support@newrelic.com"
15
- s.executables = ["mongrel_rpm", "newrelic_cmd", "newrelic"]
15
+ s.executables = ["mongrel_rpm", "newrelic", "newrelic_cmd"]
16
16
  s.extra_rdoc_files = [
17
17
  "CHANGELOG",
18
18
  "LICENSE",
@@ -29,10 +29,6 @@ Gem::Specification.new do |s|
29
29
  "cert/cacert.pem",
30
30
  "cert/oldsite.pem",
31
31
  "cert/site.pem",
32
- "dolores_rpm-3.2.0.2.gem",
33
- "dolores_rpm-3.2.0.5.gem",
34
- "dolores_rpm-3.3.4.fork.gem",
35
- "dolores_rpm.gemspec",
36
32
  "install.rb",
37
33
  "lib/conditional_vendored_dependency_detection.rb",
38
34
  "lib/conditional_vendored_metric_parser.rb",
@@ -46,6 +42,7 @@ Gem::Specification.new do |s|
46
42
  "lib/new_relic/agent/error_collector.rb",
47
43
  "lib/new_relic/agent/instrumentation.rb",
48
44
  "lib/new_relic/agent/instrumentation/active_merchant.rb",
45
+ "lib/new_relic/agent/instrumentation/active_record.rb",
49
46
  "lib/new_relic/agent/instrumentation/acts_as_solr.rb",
50
47
  "lib/new_relic/agent/instrumentation/authlogic.rb",
51
48
  "lib/new_relic/agent/instrumentation/controller_instrumentation.rb",
@@ -62,10 +59,8 @@ Gem::Specification.new do |s|
62
59
  "lib/new_relic/agent/instrumentation/rack.rb",
63
60
  "lib/new_relic/agent/instrumentation/rails/action_controller.rb",
64
61
  "lib/new_relic/agent/instrumentation/rails/action_web_service.rb",
65
- "lib/new_relic/agent/instrumentation/rails/active_record_instrumentation.rb",
66
62
  "lib/new_relic/agent/instrumentation/rails/errors.rb",
67
63
  "lib/new_relic/agent/instrumentation/rails3/action_controller.rb",
68
- "lib/new_relic/agent/instrumentation/rails3/active_record_instrumentation.rb",
69
64
  "lib/new_relic/agent/instrumentation/rails3/errors.rb",
70
65
  "lib/new_relic/agent/instrumentation/sinatra.rb",
71
66
  "lib/new_relic/agent/instrumentation/sunspot.rb",
@@ -79,9 +74,11 @@ Gem::Specification.new do |s|
79
74
  "lib/new_relic/agent/shim_agent.rb",
80
75
  "lib/new_relic/agent/sql_sampler.rb",
81
76
  "lib/new_relic/agent/stats_engine.rb",
77
+ "lib/new_relic/agent/stats_engine/gc_profiler.rb",
82
78
  "lib/new_relic/agent/stats_engine/metric_stats.rb",
83
79
  "lib/new_relic/agent/stats_engine/samplers.rb",
84
80
  "lib/new_relic/agent/stats_engine/transactions.rb",
81
+ "lib/new_relic/agent/transaction_info.rb",
85
82
  "lib/new_relic/agent/transaction_sample_builder.rb",
86
83
  "lib/new_relic/agent/transaction_sampler.rb",
87
84
  "lib/new_relic/agent/worker_loop.rb",
@@ -132,10 +129,12 @@ Gem::Specification.new do |s|
132
129
  "lib/tasks/install.rake",
133
130
  "lib/tasks/tests.rake",
134
131
  "newrelic.yml",
132
+ "dolores_rpm.gemspec",
135
133
  "recipes/newrelic.rb",
136
134
  "test/active_record_fixtures.rb",
137
135
  "test/config/newrelic.yml",
138
136
  "test/config/test_control.rb",
137
+ "test/fixtures/proc_cpuinfo.txt",
139
138
  "test/new_relic/agent/agent/connect_test.rb",
140
139
  "test/new_relic/agent/agent/start_test.rb",
141
140
  "test/new_relic/agent/agent/start_worker_thread_test.rb",
@@ -171,6 +170,7 @@ Gem::Specification.new do |s|
171
170
  "test/new_relic/agent/stats_engine/metric_stats_test.rb",
172
171
  "test/new_relic/agent/stats_engine/samplers_test.rb",
173
172
  "test/new_relic/agent/stats_engine_test.rb",
173
+ "test/new_relic/agent/transaction_info_test.rb",
174
174
  "test/new_relic/agent/transaction_sample_builder_test.rb",
175
175
  "test/new_relic/agent/transaction_sampler_test.rb",
176
176
  "test/new_relic/agent/worker_loop_test.rb",
@@ -185,6 +185,7 @@ Gem::Specification.new do |s|
185
185
  "test/new_relic/delayed_job_injection_test.rb",
186
186
  "test/new_relic/local_environment_test.rb",
187
187
  "test/new_relic/metric_data_test.rb",
188
+ "test/new_relic/metric_parser/metric_parser_test.rb",
188
189
  "test/new_relic/metric_spec_test.rb",
189
190
  "test/new_relic/rack/all_test.rb",
190
191
  "test/new_relic/rack/browser_monitoring_test.rb",
@@ -200,6 +201,9 @@ Gem::Specification.new do |s|
200
201
  "test/new_relic/transaction_sample_subtest_test.rb",
201
202
  "test/new_relic/transaction_sample_test.rb",
202
203
  "test/new_relic/version_number_test.rb",
204
+ "test/script/build_test_gem.sh",
205
+ "test/script/ci.sh",
206
+ "test/script/ci_bench.sh",
203
207
  "test/test_contexts.rb",
204
208
  "test/test_helper.rb",
205
209
  "ui/helpers/developer_mode_helper.rb",
@@ -281,7 +285,7 @@ Gem::Specification.new do |s|
281
285
  "vendor/gems/metric_parser-0.1.0.pre1/lib/new_relic/metric_parser/web_transaction.rb"
282
286
  ]
283
287
  s.homepage = "http://www.github.com/newrelic/rpm"
284
- s.post_install_message = "\nPLEASE NOTE:\n\nDeveloper Mode is now a Rack middleware.\n\nDeveloper Mode is no longer available in Rails 2.1 and earlier.\nHowever, starting in version 2.12 you can use Developer Mode in any\nRack based framework, in addition to Rails. To install developer mode\nin a non-Rails application, just add NewRelic::Rack::DeveloperMode to\nyour middleware stack.\n\nIf you are using JRuby, we recommend using at least version 1.4 or \nlater because of issues with the implementation of the timeout library.\n\nRefer to the README.md file for more information.\n\nPlease see http://github.com/newrelic/rpm/blob/master/CHANGELOG\nfor a complete description of the features and enhancements available\nin version 3.2 of the Ruby Agent.\n \n"
288
+ s.post_install_message = "\nPLEASE NOTE:\n\nDeveloper Mode is now a Rack middleware.\n\nDeveloper Mode is no longer available in Rails 2.1 and earlier.\nHowever, starting in version 2.12 you can use Developer Mode in any\nRack based framework, in addition to Rails. To install developer mode\nin a non-Rails application, just add NewRelic::Rack::DeveloperMode to\nyour middleware stack.\n\nIf you are using JRuby, we recommend using at least version 1.4 or \nlater because of issues with the implementation of the timeout library.\n\nRefer to the README.md file for more information.\n\nPlease see http://github.com/newrelic/rpm/blob/master/CHANGELOG\nfor a complete description of the features and enhancements available\nin version 3.3 of the Ruby Agent.\n \n"
285
289
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "New Relic Ruby Agent"]
286
290
  s.require_paths = ["lib"]
287
291
  s.rubygems_version = "1.8.23"
@@ -37,7 +37,6 @@ module NewRelic
37
37
  @transaction_sampler = NewRelic::Agent::TransactionSampler.new
38
38
  @sql_sampler = NewRelic::Agent::SqlSampler.new
39
39
  @stats_engine.transaction_sampler = @transaction_sampler
40
- @stats_engine.sql_sampler = @sql_sampler
41
40
  @error_collector = NewRelic::Agent::ErrorCollector.new
42
41
  @connect_attempts = 0
43
42
 
@@ -130,9 +129,9 @@ module NewRelic
130
129
  if options['exception']
131
130
  e = options['exception']
132
131
  elsif options['error_message']
133
- e = Exception.new options['error_message']
132
+ e = StandardError.new options['error_message']
134
133
  else
135
- e = Exception.new 'Unknown Error'
134
+ e = StandardError.new 'Unknown Error'
136
135
  end
137
136
  error_collector.notice_error e, :uri => options['uri'], :metric => metric
138
137
  end
@@ -539,7 +538,7 @@ module NewRelic
539
538
  handle_force_disconnect(e)
540
539
  rescue NewRelic::Agent::ServerConnectionException => e
541
540
  handle_server_connection_problem(e)
542
- rescue Exception => e
541
+ rescue => e
543
542
  handle_other_error(e)
544
543
  end
545
544
 
@@ -775,13 +774,15 @@ module NewRelic
775
774
  # Ask the server for permission to send transaction samples.
776
775
  # determined by subscription license.
777
776
  @transaction_sampler.config['enabled'] = server_enabled
778
- @sql_sampler.disable unless @transaction_sampler.config['enabled']
779
-
777
+ @sql_sampler.configure!
780
778
  @should_send_samples = @config_should_send_samples && server_enabled
781
-
779
+
782
780
  if @should_send_samples
783
781
  # I don't think this is ever true, but...
784
782
  enable_random_samples!(sample_rate) if @should_send_random_samples
783
+
784
+ @transaction_sampler.slow_capture_threshold = @slowest_transaction_threshold
785
+
785
786
  log.debug "Transaction tracing threshold is #{@slowest_transaction_threshold} seconds."
786
787
  else
787
788
  log.debug "Transaction traces will not be sent to the New Relic service."
@@ -862,6 +863,11 @@ module NewRelic
862
863
  @beacon_configuration = BeaconConfiguration.new(config_data)
863
864
  @server_side_config_enabled = config_data['listen_to_server_config']
864
865
 
866
+ if @server_side_config_enabled
867
+ log.info "Using config from server"
868
+ log.debug "Server provided config: #{config_data.inspect}"
869
+ end
870
+
865
871
  control.merge_server_side_config(config_data) if @server_side_config_enabled
866
872
  config_transaction_tracer
867
873
  log_connection!(config_data)
@@ -1042,7 +1048,7 @@ module NewRelic
1042
1048
  # FIXME add the code to try to resend if our connection is down
1043
1049
  sql_traces = @sql_sampler.harvest
1044
1050
  unless sql_traces.empty?
1045
- log.debug "Sending (#{sql_traces.count}) sql traces"
1051
+ log.debug "Sending (#{sql_traces.size}) sql traces"
1046
1052
  begin
1047
1053
  response = invoke_remote :sql_trace_data, sql_traces
1048
1054
  # log.debug "Sql trace response: #{response}"
@@ -1063,6 +1069,7 @@ module NewRelic
1063
1069
  unless @traces.empty?
1064
1070
  now = Time.now
1065
1071
  log.debug "Sending (#{@traces.length}) transaction traces"
1072
+
1066
1073
  begin
1067
1074
  options = { :keep_backtraces => true }
1068
1075
  options[:record_sql] = @record_sql unless @record_sql == :off
@@ -1134,16 +1141,16 @@ module NewRelic
1134
1141
  def compress_data(object)
1135
1142
  dump = Marshal.dump(object)
1136
1143
 
1137
- # this checks to make sure mongrel won't choke on big uploads
1138
- check_post_size(dump)
1139
-
1140
1144
  dump_size = dump.size
1141
1145
 
1142
1146
  return [dump, 'identity'] if dump_size < (64*1024)
1143
1147
 
1144
- compression = dump_size < 2000000 ? Zlib::BEST_SPEED : Zlib::BEST_COMPRESSION
1148
+ compressed_dump = Zlib::Deflate.deflate(dump, Zlib::DEFAULT_COMPRESSION)
1149
+
1150
+ # this checks to make sure mongrel won't choke on big uploads
1151
+ check_post_size(compressed_dump)
1145
1152
 
1146
- [Zlib::Deflate.deflate(dump, compression), 'deflate']
1153
+ [compressed_dump, 'deflate']
1147
1154
  end
1148
1155
 
1149
1156
  # Raises a PostTooBigException if the post_string is longer
@@ -1265,7 +1272,7 @@ module NewRelic
1265
1272
  def save_or_transmit_data
1266
1273
  if NewRelic::DataSerialization.should_send_data?
1267
1274
  log.debug "Sending data to New Relic Service"
1268
- NewRelic::Agent.load_data
1275
+ NewRelic::Agent.load_data unless NewRelic::Control.instance.disable_serialization?
1269
1276
  harvest_and_send_errors
1270
1277
  harvest_and_send_slowest_sample
1271
1278
  harvest_and_send_slowest_sql
@@ -1274,6 +1281,13 @@ module NewRelic
1274
1281
  log.debug "Serializing agent data to disk"
1275
1282
  NewRelic::Agent.save_data
1276
1283
  end
1284
+ rescue => e
1285
+ NewRelic::Control.instance.disable_serialization = true
1286
+ NewRelic::Control.instance.log.warn("Disabling serialization: #{e.message}")
1287
+ retry_count ||= 0
1288
+ retry_count += 1
1289
+ retry unless retry_count > 1
1290
+ raise e
1277
1291
  end
1278
1292
 
1279
1293
  # This method contacts the server to send remaining data and
@@ -28,6 +28,13 @@ module NewRelic
28
28
  # local config
29
29
  attr_reader :rum_enabled
30
30
 
31
+ # whether JSONP is used to communicate with the Beacon or not
32
+ attr_reader :rum_jsonp
33
+
34
+ # RUM footer command used for 'finish' - based on whether JSONP is
35
+ # being used. 'nrfj' for JSONP, otherwise 'nrf2'
36
+ attr_reader :finish_command
37
+
31
38
  # A static javascript header that is identical for every account
32
39
  # and application
33
40
  JS_HEADER = "<script type=\"text/javascript\">var NREUMQ=NREUMQ||[];NREUMQ.push([\"mark\",\"firstbyte\",new Date().getTime()]);</script>"
@@ -45,6 +52,10 @@ module NewRelic
45
52
  NewRelic::Control.instance.log.debug("Browser timing header: #{@browser_timing_header.inspect}")
46
53
  @browser_timing_static_footer = build_load_file_js(connect_data)
47
54
  NewRelic::Control.instance.log.debug("Browser timing static footer: #{@browser_timing_static_footer.inspect}")
55
+ @rum_jsonp = connect_data['rum.jsonp']
56
+ @rum_jsonp = true if @rum_jsonp.nil?
57
+ NewRelic::Control.instance.log.debug("Real User Monitoring is using JSONP protocol") if @rum_jsonp
58
+ @finish_command = @rum_jsonp ? 'nrfj' : 'nrf2'
48
59
  end
49
60
 
50
61
  # returns a memoized version of the bytes in the license key for
@@ -6,6 +6,24 @@ module NewRelic
6
6
  # javascript generation and configuration
7
7
  module BrowserMonitoring
8
8
 
9
+
10
+ class DummyMetricFrame
11
+ def initialize
12
+ @attributes = {}
13
+ end
14
+
15
+ def user_attributes
16
+ @attributes
17
+ end
18
+
19
+ def queue_time
20
+ 0.0
21
+ end
22
+ end
23
+
24
+ @@dummy_metric_frame = DummyMetricFrame.new
25
+
26
+
9
27
  # This method returns a string suitable for inclusion in a page
10
28
  # - known as 'manual instrumentation' for Real User
11
29
  # Monitoring. Can return either a script tag with associated
@@ -34,32 +52,49 @@ module NewRelic
34
52
  config = NewRelic::Agent.instance.beacon_configuration
35
53
  return "" if config.nil? || !config.rum_enabled || config.browser_monitoring_key.nil?
36
54
  return "" if !NewRelic::Agent.is_transaction_traced? || !NewRelic::Agent.is_execution_traced?
37
- generate_footer_js
55
+ generate_footer_js(config)
38
56
  end
39
57
 
40
58
  private
41
59
 
42
- def generate_footer_js
60
+ def generate_footer_js(config)
43
61
  if browser_monitoring_start_time
44
- config = NewRelic::Agent.instance.beacon_configuration
45
62
  application_id = config.application_id
46
63
  beacon = config.beacon
47
64
  license_key = config.browser_monitoring_key
48
65
 
49
- footer_js_string(beacon, license_key, application_id)
66
+ footer_js_string(config, beacon, license_key, application_id)
50
67
  else
51
68
  ''
52
69
  end
53
70
  end
54
71
 
55
72
  def browser_monitoring_transaction_name
56
- Thread.current[:newrelic_most_recent_transaction] || "<unknown>"
73
+ NewRelic::Agent::TransactionInfo.get.transaction_name
57
74
  end
58
75
 
59
76
  def browser_monitoring_start_time
60
- Thread.current[:newrelic_start_time]
77
+ NewRelic::Agent::TransactionInfo.get.start_time
61
78
  end
62
-
79
+
80
+ def metric_frame_attribute(key)
81
+ current_metric_frame.user_attributes[key] || ""
82
+ end
83
+
84
+ def current_metric_frame
85
+ Thread.current[:last_metric_frame] || @@dummy_metric_frame
86
+ end
87
+
88
+ def tt_guid
89
+ txn = NewRelic::Agent::TransactionInfo.get
90
+ return txn.guid if txn.include_guid?
91
+ ""
92
+ end
93
+
94
+ def tt_token
95
+ return NewRelic::Agent::TransactionInfo.get.token
96
+ end
97
+
63
98
  def clamp_to_positive(value)
64
99
  return 0.0 if value < 0
65
100
  value
@@ -70,12 +105,17 @@ module NewRelic
70
105
  end
71
106
 
72
107
  def browser_monitoring_queue_time
73
- clamp_to_positive((Thread.current[:newrelic_queue_time].to_f * 1000.0).round)
108
+ clamp_to_positive((current_metric_frame.queue_time.to_f * 1000.0).round)
74
109
  end
75
110
 
76
- def footer_js_string(beacon, license_key, application_id)
77
- obfuscated_transaction_name = obfuscate(browser_monitoring_transaction_name)
78
- html_safe_if_needed("<script type=\"text/javascript\">#{NewRelic::Agent.instance.beacon_configuration.browser_timing_static_footer}NREUMQ.push([\"nrf2\",\"#{beacon}\",\"#{license_key}\",#{application_id},\"#{obfuscated_transaction_name}\",#{browser_monitoring_queue_time},#{browser_monitoring_app_time},new Date().getTime()])</script>")
111
+ def footer_js_string(config, beacon, license_key, application_id)
112
+ obfuscated_transaction_name = obfuscate(config, browser_monitoring_transaction_name)
113
+
114
+ user = obfuscate(config, metric_frame_attribute(:user))
115
+ account = obfuscate(config, metric_frame_attribute(:account))
116
+ product = obfuscate(config, metric_frame_attribute(:product))
117
+
118
+ html_safe_if_needed("<script type=\"text/javascript\">#{config.browser_timing_static_footer}NREUMQ.push([\"#{config.finish_command}\",\"#{beacon}\",\"#{license_key}\",#{application_id},\"#{obfuscated_transaction_name}\",#{browser_monitoring_queue_time},#{browser_monitoring_app_time},new Date().getTime(),\"#{tt_guid}\",\"#{tt_token}\",\"#{user}\",\"#{account}\",\"#{product}\"])</script>")
79
119
  end
80
120
 
81
121
  def html_safe_if_needed(string)
@@ -86,9 +126,9 @@ module NewRelic
86
126
  end
87
127
  end
88
128
 
89
- def obfuscate(text)
129
+ def obfuscate(config, text)
90
130
  obfuscated = ""
91
- key_bytes = NewRelic::Agent.instance.beacon_configuration.license_bytes
131
+ key_bytes = config.license_bytes
92
132
  index = 0
93
133
  text.each_byte{|byte|
94
134
  obfuscated.concat((byte ^ key_bytes[index % 13].to_i))
@@ -30,7 +30,7 @@ module NewRelic
30
30
  def get_connection(config)
31
31
  ConnectionManager.instance.get_connection(config)
32
32
  end
33
-
33
+
34
34
  def close_connections
35
35
  ConnectionManager.instance.close_connections
36
36
  end
@@ -95,12 +95,12 @@ module NewRelic
95
95
 
96
96
  def handle_exception_in_explain
97
97
  yield
98
- rescue Exception => e
98
+ rescue => e
99
99
  begin
100
100
  # guarantees no throw from explain_sql
101
101
  NewRelic::Control.instance.log.error("Error getting query plan: #{e.message}")
102
102
  NewRelic::Control.instance.log.debug(e.backtrace.join("\n"))
103
- rescue Exception
103
+ rescue
104
104
  # double exception. throw up your hands
105
105
  end
106
106
  end
@@ -111,10 +111,10 @@ module NewRelic
111
111
  first_word, rest_of_statement = statement.split($;, 2)
112
112
  (first_word.upcase == 'SELECT')
113
113
  end
114
-
114
+
115
115
  class ConnectionManager
116
116
  include Singleton
117
-
117
+
118
118
  # Returns a cached connection for a given ActiveRecord
119
119
  # configuration - these are stored or reopened as needed, and if
120
120
  # we cannot get one, we ignore it and move on without explaining
@@ -187,16 +187,36 @@ module NewRelic
187
187
  end
188
188
 
189
189
  def default_sql_obfuscator(sql)
190
- sql = sql.dup
191
- # This is hardly readable. Use the unit tests.
192
- # remove single quoted strings:
193
- sql.gsub!(/'(.*?[^\\'])??'(?!')/, '?')
194
- # remove double quoted strings:
195
- sql.gsub!(/"(.*?[^\\"])??"(?!")/, '?')
196
- # replace all number literals
197
- sql.gsub!(/\d+/, "?")
198
- sql
190
+ stmt = sql.kind_of?(Statement) ? sql : Statement.new(sql)
191
+ adapter = stmt.adapter
192
+ obfuscated = remove_escaped_quotes(stmt)
193
+ obfuscated = obfuscate_single_quote_literals(obfuscated)
194
+ if !(adapter.to_s =~ /postgres/ || adapter.to_s =~ /sqlite/)
195
+ obfuscated = obfuscate_double_quote_literals(obfuscated)
196
+ end
197
+ obfuscated = obfuscate_numeric_literals(obfuscated)
198
+ obfuscated.to_s # return back to a regular String
199
+ end
200
+
201
+ def remove_escaped_quotes(sql)
202
+ sql.gsub(/\\"/, '').gsub(/\\'/, '')
199
203
  end
204
+
205
+ def obfuscate_single_quote_literals(sql)
206
+ sql.gsub(/'(?:[^']|'')*'/, '?')
207
+ end
208
+
209
+ def obfuscate_double_quote_literals(sql)
210
+ sql.gsub(/"(?:[^"]|"")*"/, '?')
211
+ end
212
+
213
+ def obfuscate_numeric_literals(sql)
214
+ sql.gsub(/\b\d+\b/, "?")
215
+ end
216
+ end
217
+
218
+ class Statement < String
219
+ attr_accessor :adapter
200
220
  end
201
221
  end
202
222
  end
@@ -223,7 +223,7 @@ module NewRelic
223
223
  exception_options = error_params_from_options(options).merge(exception_info(exception))
224
224
  add_to_error_queue(NewRelic::NoticedError.new(action_path, exception_options, exception))
225
225
  exception
226
- rescue Exception => e
226
+ rescue => e
227
227
  log.error("Error capturing an error, yodawg. #{e}")
228
228
  end
229
229
 
@@ -2,7 +2,9 @@ DependencyDetection.defer do
2
2
  @name = :active_merchant
3
3
 
4
4
  depends_on do
5
- defined?(ActiveMerchant) && defined?(ActiveMerchant::Billing)
5
+ defined?(ActiveMerchant) && defined?(ActiveMerchant::Billing) &&
6
+ defined?(ActiveMerchant::Billing::Gateway) &&
7
+ ActiveMerchant::Billing::Gateway.respond_to?(:implementations)
6
8
  end
7
9
 
8
10
  executes do
@@ -0,0 +1,137 @@
1
+ module NewRelic
2
+ module Agent
3
+ module Instrumentation
4
+ module ActiveRecord
5
+ def self.included(instrumented_class)
6
+ instrumented_class.class_eval do
7
+ unless instrumented_class.method_defined?(:log_without_newrelic_instrumentation)
8
+ alias_method :log_without_newrelic_instrumentation, :log
9
+ alias_method :log, :log_with_newrelic_instrumentation
10
+ protected :log
11
+ end
12
+ end
13
+ end
14
+
15
+ def log_with_newrelic_instrumentation(*args, &block)
16
+ if !NewRelic::Agent.is_execution_traced?
17
+ return log_without_newrelic_instrumentation(*args, &block)
18
+ end
19
+
20
+ sql, name, binds = args
21
+ metric = metric_for_name(name) || metric_for_sql(sql)
22
+
23
+ if !metric
24
+ log_without_newrelic_instrumentation(*args, &block)
25
+ else
26
+ metrics = [metric, remote_service_metric].compact
27
+ metrics += rollup_metrics_for(metric)
28
+ self.class.trace_execution_scoped(metrics) do
29
+ t0 = Time.now
30
+ begin
31
+ log_without_newrelic_instrumentation(*args, &block)
32
+ ensure
33
+ elapsed_time = (Time.now - t0).to_f
34
+ NewRelic::Agent.instance.transaction_sampler.notice_sql(sql,
35
+ @config, elapsed_time)
36
+ NewRelic::Agent.instance.sql_sampler.notice_sql(sql, metric,
37
+ @config, elapsed_time)
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def remote_service_metric
44
+ if @config && @config[:adapter]
45
+ type = @config[:adapter].sub(/\d*/, '')
46
+ host = @config[:host] || 'localhost'
47
+ "RemoteService/sql/#{type}/#{host}"
48
+ end
49
+ end
50
+
51
+ def metric_for_name(name)
52
+ if name && (parts = name.split " ") && parts.size == 2
53
+ model = parts.first
54
+ operation = parts.last.downcase
55
+ op_name = case operation
56
+ when 'load', 'count', 'exists' then 'find'
57
+ when 'indexes', 'columns' then nil # fall back to DirectSQL
58
+ when 'destroy', 'find', 'save', 'create' then operation
59
+ when 'update' then 'save'
60
+ else
61
+ if model == 'Join'
62
+ operation
63
+ end
64
+ end
65
+ "ActiveRecord/#{model}/#{op_name}" if op_name
66
+ end
67
+ end
68
+
69
+ def metric_for_sql(sql)
70
+ metric = NewRelic::Agent::Instrumentation::MetricFrame.database_metric_name
71
+ if metric.nil?
72
+ if sql =~ /^(select|update|insert|delete|show)/i
73
+ # Could not determine the model/operation so let's find a better
74
+ # metric. If it doesn't match the regex, it's probably a show
75
+ # command or some DDL which we'll ignore.
76
+ metric = "Database/SQL/#{$1.downcase}"
77
+ else
78
+ metric = "Database/SQL/other"
79
+ end
80
+ end
81
+ metric
82
+ end
83
+
84
+ def rollup_metrics_for(metric)
85
+ metrics = ["ActiveRecord/all"]
86
+ metrics << "ActiveRecord/#{$1}" if metric =~ /ActiveRecord\/\w+\/(\w+)/
87
+ metrics
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ DependencyDetection.defer do
95
+ @name = :active_record
96
+
97
+ depends_on do
98
+ defined?(ActiveRecord) && defined?(ActiveRecord::Base)
99
+ end
100
+
101
+ depends_on do
102
+ !NewRelic::Control.instance['skip_ar_instrumentation']
103
+ end
104
+
105
+ depends_on do
106
+ !NewRelic::Control.instance['disable_activerecord_instrumentation']
107
+ end
108
+
109
+ executes do
110
+ NewRelic::Agent.logger.debug 'Installing ActiveRecord instrumentation'
111
+ end
112
+
113
+ executes do
114
+ if defined?(::Rails) && ::Rails::VERSION::MAJOR.to_i == 3
115
+ Rails.configuration.after_initialize do
116
+ insert_instrumentation
117
+ end
118
+ else
119
+ insert_instrumentation
120
+ end
121
+ end
122
+
123
+ def insert_instrumentation
124
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.module_eval do
125
+ include ::NewRelic::Agent::Instrumentation::ActiveRecord
126
+ end
127
+
128
+ ActiveRecord::Base.class_eval do
129
+ class << self
130
+ add_method_tracer(:find_by_sql, 'ActiveRecord/#{self.name}/find_by_sql',
131
+ :metric => false)
132
+ add_method_tracer(:transaction, 'ActiveRecord/#{self.name}/transaction',
133
+ :metric => false)
134
+ end
135
+ end
136
+ end
137
+ end