/
browser_monitoring.rb
168 lines (134 loc) · 5.68 KB
/
browser_monitoring.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
require 'base64'
require 'new_relic/agent/beacon_configuration'
module NewRelic
module Agent
# This module contains support for Real User Monitoring - the
# javascript generation and configuration
module BrowserMonitoring
class DummyMetricFrame
def initialize
@attributes = {}
end
def user_attributes
@attributes
end
def queue_time
0.0
end
end
@@dummy_metric_frame = DummyMetricFrame.new
# This method returns a string suitable for inclusion in a page
# - known as 'manual instrumentation' for Real User
# Monitoring. Can return either a script tag with associated
# javascript, or in the case of disabled Real User Monitoring,
# an empty string
#
# This is the header string - it should be placed as high in the
# page as is reasonably possible - that is, before any style or
# javascript inclusions, but after any header-related meta tags
def browser_timing_header
return "" if NewRelic::Agent.instance.beacon_configuration.nil?
return "" if !NewRelic::Agent.is_transaction_traced? || !NewRelic::Agent.is_execution_traced?
NewRelic::Agent.instance.beacon_configuration.browser_timing_header
end
# This method returns a string suitable for inclusion in a page
# - known as 'manual instrumentation' for Real User
# Monitoring. Can return either a script tag with associated
# javascript, or in the case of disabled Real User Monitoring,
# an empty string
#
# This is the footer string - it should be placed as low in the
# page as is reasonably possible.
def browser_timing_footer
config = NewRelic::Agent.instance.beacon_configuration
return "" if config.nil? || !config.rum_enabled || config.browser_monitoring_key.nil?
return "" if !NewRelic::Agent.is_transaction_traced? || !NewRelic::Agent.is_execution_traced?
generate_footer_js(config)
end
module_function
def obfuscate(config, text)
obfuscated = ""
key_bytes = config.license_bytes
index = 0
text.each_byte{|byte|
obfuscated.concat((byte ^ key_bytes[index % 13].to_i))
index+=1
}
[obfuscated].pack("m0").gsub("\n", '')
end
def browser_monitoring_transaction_name
NewRelic::Agent::TransactionInfo.get.transaction_name
end
def browser_monitoring_queue_time
clamp_to_positive((current_metric_frame.queue_time.to_f * 1000.0).round)
end
def browser_monitoring_app_time
clamp_to_positive(((Time.now - browser_monitoring_start_time).to_f * 1000.0).round)
end
def current_metric_frame
Thread.current[:last_metric_frame] || @@dummy_metric_frame
end
def clamp_to_positive(value)
return 0.0 if value < 0
value
end
def browser_monitoring_start_time
NewRelic::Agent::TransactionInfo.get.start_time
end
def insert_mobile_response_header(request, response)
if mobile_header_found_in?(request) &&
NewRelic::Agent.instance.beacon_configuration
config = NewRelic::Agent.instance.beacon_configuration
response['X-NewRelic-Beacon-Url'] = beacon_url(request)
payload = %[ ["#{config.application_id}","#{obfuscate(config, browser_monitoring_transaction_name)}",#{browser_monitoring_queue_time},#{browser_monitoring_app_time}] ]
response['X-NewRelic-App-Server-Metrics'] = payload
end
end
def mobile_header_found_in?(request)
headers = ['HTTP_X_NEWRELIC_MOBILE_TRACE', 'X_NEWRELIC_MOBILE_TRACE',
'X-NewRelic-Mobile-Trace']
headers.inject(false){|i,m| i || (request.env[m] == 'true')}
end
def beacon_url(request)
config = NewRelic::Agent.instance.beacon_configuration
"#{request.scheme || 'http'}://#{config.beacon}/mobile/1/#{config.browser_monitoring_key}"
end
private
def generate_footer_js(config)
if browser_monitoring_start_time
application_id = config.application_id
beacon = config.beacon
license_key = config.browser_monitoring_key
footer_js_string(config, beacon, license_key, application_id)
else
''
end
end
def metric_frame_attribute(key)
current_metric_frame.user_attributes[key] || ""
end
def tt_guid
txn = NewRelic::Agent::TransactionInfo.get
return txn.guid if txn.include_guid?
""
end
def tt_token
return NewRelic::Agent::TransactionInfo.get.token
end
def footer_js_string(config, beacon, license_key, application_id)
obfuscated_transaction_name = obfuscate(config, browser_monitoring_transaction_name)
user = obfuscate(config, metric_frame_attribute(:user))
account = obfuscate(config, metric_frame_attribute(:account))
product = obfuscate(config, metric_frame_attribute(:product))
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>")
end
def html_safe_if_needed(string)
if string.respond_to?(:html_safe)
string.html_safe
else
string
end
end
end
end
end