newrelic_rpm 3.7.0.174.beta → 3.7.0.177

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +27 -4
  3. data/bin/nrdebug +10 -4
  4. data/lib/new_relic/agent.rb +33 -11
  5. data/lib/new_relic/agent/agent.rb +83 -120
  6. data/lib/new_relic/agent/agent_logger.rb +28 -16
  7. data/lib/new_relic/agent/audit_logger.rb +3 -4
  8. data/lib/new_relic/agent/autostart.rb +20 -8
  9. data/lib/new_relic/agent/commands/agent_command_router.rb +26 -17
  10. data/lib/new_relic/agent/commands/thread_profiler_session.rb +2 -2
  11. data/lib/new_relic/agent/configuration/default_source.rb +146 -59
  12. data/lib/new_relic/agent/configuration/manager.rb +3 -3
  13. data/lib/new_relic/agent/cross_app_monitor.rb +15 -40
  14. data/lib/new_relic/agent/cross_app_tracing.rb +20 -12
  15. data/lib/new_relic/agent/database.rb +24 -0
  16. data/lib/new_relic/agent/error_collector.rb +6 -2
  17. data/lib/new_relic/agent/instrumentation/merb/controller.rb +3 -1
  18. data/lib/new_relic/agent/javascript_instrumentor.rb +187 -0
  19. data/lib/new_relic/agent/new_relic_service.rb +30 -22
  20. data/lib/new_relic/agent/obfuscator.rb +48 -0
  21. data/lib/new_relic/agent/request_sampler.rb +5 -13
  22. data/lib/new_relic/agent/shim_agent.rb +1 -0
  23. data/lib/new_relic/agent/sql_sampler.rb +15 -5
  24. data/lib/new_relic/agent/stats_engine/metric_stats.rb +9 -4
  25. data/lib/new_relic/agent/transaction.rb +0 -1
  26. data/lib/new_relic/agent/transaction_sampler.rb +28 -16
  27. data/lib/new_relic/agent/transaction_state.rb +9 -0
  28. data/lib/new_relic/agent/transaction_timings.rb +5 -1
  29. data/lib/new_relic/agent/worker_loop.rb +0 -10
  30. data/lib/new_relic/cli/deployments.rb +1 -1
  31. data/lib/new_relic/control/instance_methods.rb +1 -1
  32. data/lib/new_relic/helper.rb +3 -1
  33. data/lib/new_relic/rack/browser_monitoring.rb +1 -2
  34. data/lib/new_relic/transaction_sample.rb +11 -13
  35. data/lib/newrelic_rpm.rb +1 -0
  36. data/test/agent_helper.rb +20 -5
  37. data/test/environments/lib/environments/runner.rb +1 -0
  38. data/test/helpers/file_searching.rb +28 -0
  39. data/test/multiverse/lib/multiverse/suite.rb +36 -19
  40. data/test/multiverse/suites/agent_only/collector_exception_handling_test.rb +49 -0
  41. data/test/multiverse/suites/agent_only/http_response_code_test.rb +2 -2
  42. data/test/multiverse/suites/agent_only/rum_instrumentation_test.rb +4 -2
  43. data/test/multiverse/suites/agent_only/service_timeout_test.rb +1 -1
  44. data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +7 -4
  45. data/test/multiverse/suites/agent_only/thread_profiling_test.rb +2 -1
  46. data/test/multiverse/suites/rails/error_tracing_test.rb +34 -4
  47. data/test/multiverse/suites/rails/ignore_test.rb +1 -1
  48. data/test/multiverse/suites/rails/request_statistics_test.rb +1 -3
  49. data/test/multiverse/suites/sequel/sequel_instrumentation_test.rb +10 -7
  50. data/test/multiverse/suites/sinatra/ignoring_test.rb +1 -1
  51. data/test/new_relic/agent/agent/start_worker_thread_test.rb +1 -1
  52. data/test/new_relic/agent/agent_logger_test.rb +108 -114
  53. data/test/new_relic/agent/agent_test.rb +139 -21
  54. data/test/new_relic/agent/audit_logger_test.rb +22 -20
  55. data/test/new_relic/agent/autostart_test.rb +3 -2
  56. data/test/new_relic/agent/commands/agent_command_router_test.rb +51 -32
  57. data/test/new_relic/agent/configuration/default_source_test.rb +8 -2
  58. data/test/new_relic/agent/configuration/manager_test.rb +5 -1
  59. data/test/new_relic/agent/configuration/orphan_configuration_test.rb +57 -0
  60. data/test/new_relic/agent/cross_app_monitor_test.rb +10 -26
  61. data/test/new_relic/agent/database_test.rb +32 -0
  62. data/test/new_relic/agent/error_collector_test.rb +33 -16
  63. data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +88 -71
  64. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +2 -2
  65. data/test/new_relic/agent/javascript_instrumentor_test.rb +341 -0
  66. data/test/new_relic/agent/memcache_instrumentation_test.rb +91 -89
  67. data/test/new_relic/agent/method_tracer_test.rb +1 -1
  68. data/test/new_relic/agent/obfuscator_test.rb +77 -0
  69. data/test/new_relic/agent/pipe_channel_manager_test.rb +5 -5
  70. data/test/new_relic/agent/pipe_service_test.rb +1 -1
  71. data/test/new_relic/agent/request_sampler_test.rb +21 -11
  72. data/test/new_relic/agent/sql_sampler_test.rb +52 -8
  73. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +6 -6
  74. data/test/new_relic/agent/stats_engine_test.rb +18 -2
  75. data/test/new_relic/agent/transaction_sampler_test.rb +98 -53
  76. data/test/new_relic/agent/transaction_state_test.rb +44 -0
  77. data/test/new_relic/agent/transaction_test.rb +1 -1
  78. data/test/new_relic/agent/transaction_timings_test.rb +15 -5
  79. data/test/new_relic/agent/worker_loop_test.rb +0 -9
  80. data/test/new_relic/agent_test.rb +9 -21
  81. data/test/new_relic/data_container_tests.rb +72 -0
  82. data/test/new_relic/fake_collector.rb +69 -20
  83. data/test/new_relic/http_client_test_cases.rb +17 -2
  84. data/test/new_relic/license_test.rb +6 -15
  85. data/test/new_relic/multiverse_helpers.rb +2 -3
  86. data/test/new_relic/rack/browser_monitoring_test.rb +15 -37
  87. data/test/new_relic/transaction_sample_test.rb +92 -62
  88. data/test/performance/suites/rum_autoinsertion.rb +0 -3
  89. data/test/rum/x_ua_meta_tag_spaces_around_equals.result.html +10 -0
  90. data/test/rum/x_ua_meta_tag_spaces_around_equals.source.html +10 -0
  91. data/test/test_helper.rb +9 -5
  92. metadata +29 -11
  93. metadata.gz.sig +0 -0
  94. data/lib/new_relic/agent/beacon_configuration.rb +0 -37
  95. data/lib/new_relic/agent/browser_monitoring.rb +0 -257
  96. data/test/new_relic/agent/beacon_configuration_test.rb +0 -44
  97. data/test/new_relic/agent/browser_monitoring_test.rb +0 -474
@@ -137,9 +137,9 @@ module NewRelic
137
137
  end
138
138
 
139
139
  def app_names
140
- case self[:app_name]
141
- when Array then self[:app_name]
142
- when String then self[:app_name].split(';')
140
+ case NewRelic::Agent.config[:app_name]
141
+ when Array then NewRelic::Agent.config[:app_name]
142
+ when String then NewRelic::Agent.config[:app_name].split(';')
143
143
  else []
144
144
  end
145
145
  end
@@ -22,36 +22,7 @@ module NewRelic
22
22
  }
23
23
  CONTENT_LENGTH_HEADER_KEYS = %w{Content-Length HTTP_CONTENT_LENGTH CONTENT_LENGTH}
24
24
 
25
- # Functions for obfuscating and unobfuscating header values
26
- module EncodingFunctions
27
-
28
- module_function
29
-
30
- def obfuscate_with_key(key, text)
31
- [ encode_with_key(key, text) ].pack('m').chomp.gsub(/\n/, '')
32
- end
33
-
34
- def decode_with_key(key, text)
35
- encode_with_key( key, text.unpack('m').first )
36
- end
37
-
38
- def encode_with_key(key, text)
39
- return text unless key
40
- key = key.bytes.to_a if key.respond_to?( :bytes )
41
-
42
- encoded = ""
43
- encoded.force_encoding('binary') if encoded.respond_to?( :force_encoding )
44
- index = 0
45
- text.each_byte do |byte|
46
- encoded.concat((byte ^ key[index % key.length].to_i))
47
- index+=1
48
- end
49
- encoded
50
- end
51
-
52
- end
53
- include EncodingFunctions
54
-
25
+ attr_reader :obfuscator
55
26
 
56
27
  def initialize(events = nil)
57
28
  # When we're starting up for real in the agent, we get passed the events
@@ -59,10 +30,14 @@ module NewRelic
59
30
  events ||= Agent.instance.events
60
31
 
61
32
  events.subscribe(:finished_configuring) do
62
- register_event_listeners
33
+ on_finished_configuring
63
34
  end
64
35
  end
65
36
 
37
+ def on_finished_configuring
38
+ setup_obfuscator
39
+ register_event_listeners
40
+ end
66
41
 
67
42
  # Expected sequence of events:
68
43
  # :before_call will save our cross application request id to the thread
@@ -93,6 +68,11 @@ module NewRelic
93
68
  end
94
69
  end
95
70
 
71
+ # This requires :encoding_key, so must wait until :finished_configuring
72
+ def setup_obfuscator
73
+ @obfuscator = NewRelic::Agent::Obfuscator.new(NewRelic::Agent.config[:encoding_key])
74
+ end
75
+
96
76
  def save_client_cross_app_id(request_headers)
97
77
  TransactionState.get.client_cross_app_id = decoded_id(request_headers)
98
78
  end
@@ -106,9 +86,8 @@ module NewRelic
106
86
  end
107
87
 
108
88
  def save_referring_transaction_info(request_headers)
109
- key = NewRelic::Agent.config[:encoding_key]
110
89
  txn_header = from_headers( request_headers, NEWRELIC_TXN_HEADER_KEYS ) or return
111
- txn_header = decode_with_key( key, txn_header )
90
+ txn_header = obfuscator.deobfuscate( txn_header )
112
91
  txn_info = NewRelic.json_load( txn_header )
113
92
  NewRelic::Agent.logger.debug "Referring txn_info: %p" % [ txn_info ]
114
93
 
@@ -143,9 +122,7 @@ module NewRelic
143
122
  end
144
123
 
145
124
  def cross_app_enabled?
146
- NewRelic::Agent.config[:cross_process_id] &&
147
- (NewRelic::Agent.config[:"cross_application_tracer.enabled"] ||
148
- NewRelic::Agent.config[:cross_application_tracing])
125
+ NewRelic::Agent::CrossAppTracing.cross_app_enabled?
149
126
  end
150
127
 
151
128
  # Expects an ID of format "12#345", and will only accept that!
@@ -170,8 +147,7 @@ module NewRelic
170
147
  content_length,
171
148
  transaction_guid()
172
149
  ]
173
- key = NewRelic::Agent.config[:encoding_key]
174
- payload = obfuscate_with_key( key, NewRelic.json_dump(payload) )
150
+ payload = obfuscator.obfuscate(NewRelic.json_dump(payload))
175
151
  end
176
152
 
177
153
  def set_transaction_custom_parameters
@@ -200,8 +176,7 @@ module NewRelic
200
176
  encoded_id = from_headers(request, NEWRELIC_ID_HEADER_KEYS)
201
177
  return "" if encoded_id.nil?
202
178
 
203
- key = NewRelic::Agent.config[:encoding_key]
204
- decode_with_key( key, encoded_id )
179
+ obfuscator.deobfuscate(encoded_id)
205
180
  end
206
181
 
207
182
  def content_length_from_request(request)
@@ -6,12 +6,10 @@
6
6
  module NewRelic
7
7
  module Agent
8
8
  module CrossAppTracing
9
- extend NewRelic::Agent::CrossAppMonitor::EncodingFunctions
10
9
 
11
10
  # Exception raised if there is a problem with cross app transactions.
12
11
  class Error < RuntimeError; end
13
12
 
14
-
15
13
  # The cross app response header for "outgoing" calls
16
14
  NR_APPDATA_HEADER = 'X-NewRelic-App-Data'
17
15
 
@@ -48,7 +46,6 @@ module NewRelic
48
46
  return response
49
47
  end
50
48
 
51
-
52
49
  # Set up the necessary state for cross-application tracing before the
53
50
  # given +request+ goes out.
54
51
  #
@@ -116,14 +113,24 @@ module NewRelic
116
113
  NewRelic::Agent.logger.error "Uncaught exception while finishing an HTTP request trace", err
117
114
  end
118
115
 
119
-
120
116
  # Return +true+ if cross app tracing is enabled in the config.
121
117
  def cross_app_enabled?
122
- NewRelic::Agent.config[:cross_process_id] &&
123
- (NewRelic::Agent.config[:"cross_application_tracer.enabled"] ||
124
- NewRelic::Agent.config[:cross_application_tracing])
118
+ valid_cross_process_id? &&
119
+ valid_encoding_key? &&
120
+ cross_application_tracer_enabled?
125
121
  end
126
122
 
123
+ def valid_cross_process_id?
124
+ NewRelic::Agent.config[:cross_process_id] && NewRelic::Agent.config[:cross_process_id].length > 0
125
+ end
126
+
127
+ def valid_encoding_key?
128
+ NewRelic::Agent.config[:encoding_key] && NewRelic::Agent.config[:encoding_key].length > 0
129
+ end
130
+
131
+ def cross_application_tracer_enabled?
132
+ NewRelic::Agent.config[:"cross_application_tracer.enabled"] || NewRelic::Agent.config[:cross_application_tracing]
133
+ end
127
134
 
128
135
  # Memoized fetcher for the cross app encoding key. Raises a
129
136
  # NewRelic::Agent::CrossAppTracing::Error if the key isn't configured.
@@ -132,17 +139,19 @@ module NewRelic
132
139
  raise NewRelic::Agent::CrossAppTracing::Error, "No encoding_key set."
133
140
  end
134
141
 
142
+ def obfuscator
143
+ @obfuscator ||= NewRelic::Agent::Obfuscator.new(cross_app_encoding_key)
144
+ end
135
145
 
136
146
  # Inject the X-Process header into the outgoing +request+.
137
147
  def inject_request_headers( request )
138
- key = cross_app_encoding_key()
139
148
  cross_app_id = NewRelic::Agent.config[:cross_process_id] or
140
149
  raise NewRelic::Agent::CrossAppTracing::Error, "no cross app ID configured"
141
150
  txn_guid = NewRelic::Agent::TransactionState.get.request_guid
142
151
  txn_data = NewRelic.json_dump([ txn_guid, false ])
143
152
 
144
- request[ NR_ID_HEADER ] = obfuscate_with_key( key, cross_app_id )
145
- request[ NR_TXN_HEADER ] = obfuscate_with_key( key, txn_data )
153
+ request[ NR_ID_HEADER ] = obfuscator.obfuscate( cross_app_id )
154
+ request[ NR_TXN_HEADER ] = obfuscator.obfuscate( txn_data )
146
155
 
147
156
  rescue NewRelic::Agent::CrossAppTracing::Error => err
148
157
  NewRelic::Agent.logger.debug "Not injecting x-process header", err
@@ -254,8 +263,7 @@ module NewRelic
254
263
  raise NewRelic::Agent::CrossAppTracing::Error,
255
264
  "Can't derive metrics for response: no #{NR_APPDATA_HEADER} header!"
256
265
 
257
- key = cross_app_encoding_key()
258
- decoded_appdata = decode_with_key( key, appdata )
266
+ decoded_appdata = obfuscator.deobfuscate( appdata )
259
267
  decoded_appdata.set_encoding( ::Encoding::UTF_8 ) if
260
268
  decoded_appdata.respond_to?( :set_encoding )
261
269
 
@@ -21,8 +21,22 @@ module NewRelic
21
21
 
22
22
  module Agent
23
23
  module Database
24
+ MAX_QUERY_LENGTH = 16384
25
+
24
26
  extend self
25
27
 
28
+ def capture_query(query)
29
+ Helper.correctly_encoded(truncate_query(query))
30
+ end
31
+
32
+ def truncate_query(query)
33
+ if query.length > (MAX_QUERY_LENGTH - 4)
34
+ query[0..MAX_QUERY_LENGTH - 4] + '...'
35
+ else
36
+ query
37
+ end
38
+ end
39
+
26
40
  def obfuscate_sql(sql)
27
41
  Obfuscator.instance.obfuscator.call(sql)
28
42
  end
@@ -46,6 +60,16 @@ module NewRelic
46
60
  end
47
61
  end
48
62
 
63
+ RECORD_FOR = [:raw, :obfuscated].freeze
64
+
65
+ def should_record_sql?
66
+ RECORD_FOR.include?(record_sql_method)
67
+ end
68
+
69
+ def should_collect_explain_plans?
70
+ should_record_sql? && Agent.config[:'transaction_tracer.explain_enabled']
71
+ end
72
+
49
73
  def get_connection(config, &connector)
50
74
  ConnectionManager.instance.get_connection(config, &connector)
51
75
  end
@@ -163,7 +163,11 @@ module NewRelic
163
163
  # If anything else is left over, we treat it like a custom param
164
164
  def custom_params_from_opts(options)
165
165
  # If anything else is left over, treat it like a custom param:
166
- fetch_from_options(options, :custom_params, {}).merge(options)
166
+ if Agent.config[:'capture_attributes.traces']
167
+ fetch_from_options(options, :custom_params, {}).merge(options)
168
+ else
169
+ {}
170
+ end
167
171
  end
168
172
 
169
173
  # takes the request parameters out of the options hash, and
@@ -306,7 +310,7 @@ module NewRelic
306
310
 
307
311
  # Get the errors currently queued up. Unsent errors are left
308
312
  # over from a previous unsuccessful attempt to send them to the server.
309
- def harvest_errors
313
+ def harvest!
310
314
  @lock.synchronize do
311
315
  errors = @errors
312
316
  @errors = []
@@ -32,12 +32,14 @@ DependencyDetection.defer do
32
32
  self.send attr_name
33
33
  end
34
34
 
35
- protected
36
35
  # determine the path that is used in the metric name for
37
36
  # the called controller action
38
37
  def newrelic_metric_path
39
38
  "#{controller_name}/#{action_name}"
40
39
  end
40
+
41
+ protected
42
+
41
43
  alias_method :perform_action_without_newrelic_trace, :_dispatch
42
44
  alias_method :_dispatch, :perform_action_with_newrelic_trace
43
45
  end
@@ -0,0 +1,187 @@
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 'base64'
6
+ require 'new_relic/agent/obfuscator'
7
+ require 'new_relic/agent/transaction_timings'
8
+
9
+ module NewRelic
10
+ module Agent
11
+ class JavascriptInstrumentor
12
+ include NewRelic::Coerce
13
+
14
+ RUM_KEY_LENGTH = 13
15
+
16
+ def initialize(event_listener)
17
+ event_listener.subscribe(:finished_configuring, &method(:log_configuration))
18
+ end
19
+
20
+ def log_configuration
21
+ NewRelic::Agent.logger.debug("JS agent loader requested: #{NewRelic::Agent.config[:'browser_monitoring.loader']}",
22
+ "JS agent loader debug: #{NewRelic::Agent.config[:'browser_monitoring.debug']}",
23
+ "JS agent loader version: #{NewRelic::Agent.config[:'browser_monitoring.loader_version']}")
24
+
25
+ if !NewRelic::Agent.config[:'rum.enabled']
26
+ NewRelic::Agent.logger.debug("Real User Monitoring is disabled for this agent. Edit your configuration to change this.")
27
+ end
28
+ end
29
+
30
+ def enabled?
31
+ Agent.config[:'rum.enabled'] && !!Agent.config[:beacon]
32
+ end
33
+
34
+ def obfuscator
35
+ @obfuscator ||= NewRelic::Agent::Obfuscator.new(NewRelic::Agent.config[:license_key], RUM_KEY_LENGTH)
36
+ end
37
+
38
+ def current_transaction
39
+ NewRelic::Agent::TransactionState.get.transaction
40
+ end
41
+
42
+ def insert_js?
43
+ if !enabled?
44
+ ::NewRelic::Agent.logger.log_once(:debug, :js_agent_disabled,
45
+ "JS agent instrumentation is disabled.")
46
+ false
47
+ elsif missing_config?(:js_agent_loader)
48
+ ::NewRelic::Agent.logger.log_once(:debug, :missing_js_agent_loader,
49
+ "Missing :js_agent_loader. Skipping browser instrumentation.")
50
+ false
51
+ elsif missing_config?(:beacon)
52
+ ::NewRelic::Agent.logger.log_once(:debug, :missing_beacon,
53
+ "Beacon configuration not received (yet?). Skipping browser instrumentation.")
54
+ false
55
+ elsif missing_config?(:browser_key)
56
+ ::NewRelic::Agent.logger.log_once(:debug, :missing_browser_key,
57
+ "Browser key is not set. Skipping browser instrumentation.")
58
+ false
59
+ elsif !current_transaction
60
+ ::NewRelic::Agent.logger.debug "Not in transaction. Skipping browser instrumentation."
61
+ false
62
+ elsif !::NewRelic::Agent.is_transaction_traced?
63
+ ::NewRelic::Agent.logger.debug "Transaction is not traced. Skipping browser instrumentation."
64
+ false
65
+ elsif !::NewRelic::Agent.is_execution_traced?
66
+ ::NewRelic::Agent.logger.debug "Execution is not traced. Skipping browser instrumentation."
67
+ false
68
+ elsif ::NewRelic::Agent::TransactionState.get.request_ignore_enduser
69
+ ::NewRelic::Agent.logger.debug "Ignore end user for this transaction is set. Skipping browser instrumentation."
70
+ false
71
+ else
72
+ true
73
+ end
74
+ end
75
+
76
+ def missing_config?(key)
77
+ value = NewRelic::Agent.config[key]
78
+ value.nil? || value.empty?
79
+ end
80
+
81
+ def browser_timing_header
82
+ return "" unless insert_js?
83
+ browser_timing_config + browser_timing_loader
84
+ end
85
+
86
+ # NOTE: Internal prototyping often overrides this, so leave name stable!
87
+ def browser_timing_loader
88
+ html_safe_if_needed("\n<script type=\"text/javascript\">#{Agent.config[:js_agent_loader]}</script>")
89
+ end
90
+
91
+ # NOTE: Internal prototyping often overrides this, so leave name stable!
92
+ def browser_timing_config
93
+ NewRelic::Agent::Transaction.freeze_name
94
+ data = data_for_js_agent
95
+ json = NewRelic.json_dump(data)
96
+ html_safe_if_needed("\n<script type=\"text/javascript\">window.NREUM||(NREUM={});NREUM.info=#{json}</script>")
97
+ end
98
+
99
+ BEACON_KEY = "beacon".freeze
100
+ ERROR_BEACON_KEY = "errorBeacon".freeze
101
+ LICENSE_KEY_KEY = "licenseKey".freeze
102
+ APPLICATIONID_KEY = "applicationID".freeze
103
+ TRANSACTION_NAME_KEY = "transactionName".freeze
104
+ QUEUE_TIME_KEY = "queueTime".freeze
105
+ APPLICATION_TIME_KEY = "applicationTime".freeze
106
+ TT_GUID_KEY = "ttGuid".freeze
107
+ AGENT_TOKEN_KEY = "agentToken".freeze
108
+ AGENT_KEY = "agent".freeze
109
+ EXTRA_KEY = "extra".freeze
110
+ SSL_FOR_HTTP_KEY = "sslForHttp".freeze
111
+
112
+ # NOTE: Internal prototyping may override this, so leave name stable!
113
+ def data_for_js_agent
114
+ state = NewRelic::Agent::TransactionState.get
115
+ timings = state.timings
116
+
117
+ data = {
118
+ BEACON_KEY => NewRelic::Agent.config[:beacon],
119
+ ERROR_BEACON_KEY => NewRelic::Agent.config[:error_beacon],
120
+ LICENSE_KEY_KEY => NewRelic::Agent.config[:browser_key],
121
+ APPLICATIONID_KEY => NewRelic::Agent.config[:application_id],
122
+ TRANSACTION_NAME_KEY => obfuscator.obfuscate(timings.transaction_name_or_unknown),
123
+ QUEUE_TIME_KEY => timings.queue_time_in_millis,
124
+ APPLICATION_TIME_KEY => timings.app_time_in_millis,
125
+ TT_GUID_KEY => state.request_guid_to_include,
126
+ AGENT_TOKEN_KEY => state.request_token,
127
+ AGENT_KEY => NewRelic::Agent.config[:js_agent_file],
128
+ EXTRA_KEY => obfuscator.obfuscate(formatted_extra_parameter_for_js_agent)
129
+ }
130
+ add_ssl_for_http(data)
131
+
132
+ data
133
+ end
134
+
135
+ def add_ssl_for_http(data)
136
+ ssl_for_http = NewRelic::Agent.config[:'browser_monitoring.ssl_for_http']
137
+ unless ssl_for_http.nil?
138
+ data[SSL_FOR_HTTP_KEY] = ssl_for_http
139
+ end
140
+ end
141
+
142
+ # NOTE: Internal prototyping may override this, so leave name stable!
143
+ def data_for_js_agent_extra_parameter
144
+ return {} unless include_custom_parameters_in_extra?
145
+ current_transaction.custom_parameters.dup
146
+ end
147
+
148
+ def include_custom_parameters_in_extra?
149
+ current_transaction &&
150
+ NewRelic::Agent.config[:'analytics_events.enabled'] &&
151
+ NewRelic::Agent.config[:'capture_attributes.page_view_events']
152
+ end
153
+
154
+ def formatted_extra_parameter_for_js_agent
155
+ format_extra_data(data_for_js_agent_extra_parameter)
156
+ end
157
+
158
+ # Format the props using semicolon separated pairs separated by '=':
159
+ # product=pro;user=bill@microsoft.com
160
+ def format_extra_data(extra_props)
161
+ event_params(extra_props).
162
+ map {|k,v| format_pair(k, v)}.
163
+ join(';')
164
+ end
165
+
166
+ def format_pair(key, value)
167
+ key = escape_special_characters(key)
168
+ value = format_value(value)
169
+ "#{key}=#{value}"
170
+ end
171
+
172
+ def escape_special_characters(string)
173
+ string.to_s.tr("\";=", "':-" )
174
+ end
175
+
176
+ def format_value(v)
177
+ v = "##{v}" if v.is_a?(Numeric)
178
+ escape_special_characters(v)
179
+ end
180
+
181
+ def html_safe_if_needed(string)
182
+ string = string.html_safe if string.respond_to?(:html_safe)
183
+ string
184
+ end
185
+ end
186
+ end
187
+ end