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.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +27 -4
- data/bin/nrdebug +10 -4
- data/lib/new_relic/agent.rb +33 -11
- data/lib/new_relic/agent/agent.rb +83 -120
- data/lib/new_relic/agent/agent_logger.rb +28 -16
- data/lib/new_relic/agent/audit_logger.rb +3 -4
- data/lib/new_relic/agent/autostart.rb +20 -8
- data/lib/new_relic/agent/commands/agent_command_router.rb +26 -17
- data/lib/new_relic/agent/commands/thread_profiler_session.rb +2 -2
- data/lib/new_relic/agent/configuration/default_source.rb +146 -59
- data/lib/new_relic/agent/configuration/manager.rb +3 -3
- data/lib/new_relic/agent/cross_app_monitor.rb +15 -40
- data/lib/new_relic/agent/cross_app_tracing.rb +20 -12
- data/lib/new_relic/agent/database.rb +24 -0
- data/lib/new_relic/agent/error_collector.rb +6 -2
- data/lib/new_relic/agent/instrumentation/merb/controller.rb +3 -1
- data/lib/new_relic/agent/javascript_instrumentor.rb +187 -0
- data/lib/new_relic/agent/new_relic_service.rb +30 -22
- data/lib/new_relic/agent/obfuscator.rb +48 -0
- data/lib/new_relic/agent/request_sampler.rb +5 -13
- data/lib/new_relic/agent/shim_agent.rb +1 -0
- data/lib/new_relic/agent/sql_sampler.rb +15 -5
- data/lib/new_relic/agent/stats_engine/metric_stats.rb +9 -4
- data/lib/new_relic/agent/transaction.rb +0 -1
- data/lib/new_relic/agent/transaction_sampler.rb +28 -16
- data/lib/new_relic/agent/transaction_state.rb +9 -0
- data/lib/new_relic/agent/transaction_timings.rb +5 -1
- data/lib/new_relic/agent/worker_loop.rb +0 -10
- data/lib/new_relic/cli/deployments.rb +1 -1
- data/lib/new_relic/control/instance_methods.rb +1 -1
- data/lib/new_relic/helper.rb +3 -1
- data/lib/new_relic/rack/browser_monitoring.rb +1 -2
- data/lib/new_relic/transaction_sample.rb +11 -13
- data/lib/newrelic_rpm.rb +1 -0
- data/test/agent_helper.rb +20 -5
- data/test/environments/lib/environments/runner.rb +1 -0
- data/test/helpers/file_searching.rb +28 -0
- data/test/multiverse/lib/multiverse/suite.rb +36 -19
- data/test/multiverse/suites/agent_only/collector_exception_handling_test.rb +49 -0
- data/test/multiverse/suites/agent_only/http_response_code_test.rb +2 -2
- data/test/multiverse/suites/agent_only/rum_instrumentation_test.rb +4 -2
- data/test/multiverse/suites/agent_only/service_timeout_test.rb +1 -1
- data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +7 -4
- data/test/multiverse/suites/agent_only/thread_profiling_test.rb +2 -1
- data/test/multiverse/suites/rails/error_tracing_test.rb +34 -4
- data/test/multiverse/suites/rails/ignore_test.rb +1 -1
- data/test/multiverse/suites/rails/request_statistics_test.rb +1 -3
- data/test/multiverse/suites/sequel/sequel_instrumentation_test.rb +10 -7
- data/test/multiverse/suites/sinatra/ignoring_test.rb +1 -1
- data/test/new_relic/agent/agent/start_worker_thread_test.rb +1 -1
- data/test/new_relic/agent/agent_logger_test.rb +108 -114
- data/test/new_relic/agent/agent_test.rb +139 -21
- data/test/new_relic/agent/audit_logger_test.rb +22 -20
- data/test/new_relic/agent/autostart_test.rb +3 -2
- data/test/new_relic/agent/commands/agent_command_router_test.rb +51 -32
- data/test/new_relic/agent/configuration/default_source_test.rb +8 -2
- data/test/new_relic/agent/configuration/manager_test.rb +5 -1
- data/test/new_relic/agent/configuration/orphan_configuration_test.rb +57 -0
- data/test/new_relic/agent/cross_app_monitor_test.rb +10 -26
- data/test/new_relic/agent/database_test.rb +32 -0
- data/test/new_relic/agent/error_collector_test.rb +33 -16
- data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +88 -71
- data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +2 -2
- data/test/new_relic/agent/javascript_instrumentor_test.rb +341 -0
- data/test/new_relic/agent/memcache_instrumentation_test.rb +91 -89
- data/test/new_relic/agent/method_tracer_test.rb +1 -1
- data/test/new_relic/agent/obfuscator_test.rb +77 -0
- data/test/new_relic/agent/pipe_channel_manager_test.rb +5 -5
- data/test/new_relic/agent/pipe_service_test.rb +1 -1
- data/test/new_relic/agent/request_sampler_test.rb +21 -11
- data/test/new_relic/agent/sql_sampler_test.rb +52 -8
- data/test/new_relic/agent/stats_engine/metric_stats_test.rb +6 -6
- data/test/new_relic/agent/stats_engine_test.rb +18 -2
- data/test/new_relic/agent/transaction_sampler_test.rb +98 -53
- data/test/new_relic/agent/transaction_state_test.rb +44 -0
- data/test/new_relic/agent/transaction_test.rb +1 -1
- data/test/new_relic/agent/transaction_timings_test.rb +15 -5
- data/test/new_relic/agent/worker_loop_test.rb +0 -9
- data/test/new_relic/agent_test.rb +9 -21
- data/test/new_relic/data_container_tests.rb +72 -0
- data/test/new_relic/fake_collector.rb +69 -20
- data/test/new_relic/http_client_test_cases.rb +17 -2
- data/test/new_relic/license_test.rb +6 -15
- data/test/new_relic/multiverse_helpers.rb +2 -3
- data/test/new_relic/rack/browser_monitoring_test.rb +15 -37
- data/test/new_relic/transaction_sample_test.rb +92 -62
- data/test/performance/suites/rum_autoinsertion.rb +0 -3
- data/test/rum/x_ua_meta_tag_spaces_around_equals.result.html +10 -0
- data/test/rum/x_ua_meta_tag_spaces_around_equals.source.html +10 -0
- data/test/test_helper.rb +9 -5
- metadata +29 -11
- metadata.gz.sig +0 -0
- data/lib/new_relic/agent/beacon_configuration.rb +0 -37
- data/lib/new_relic/agent/browser_monitoring.rb +0 -257
- data/test/new_relic/agent/beacon_configuration_test.rb +0 -44
- 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
|
141
|
-
when Array then
|
142
|
-
when String then
|
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
|
-
|
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
|
-
|
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 =
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
123
|
-
|
124
|
-
|
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 ] =
|
145
|
-
request[ NR_TXN_HEADER ] =
|
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
|
-
|
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
|
-
|
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
|
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
|