Class: OneApm::Agent::JavascriptInstrumentor

Inherits:
Object
  • Object
show all
Includes:
Coerce
Defined in:
lib/one_apm/agent/javascript_instrumentor.rb

Constant Summary collapse

OA_RUM_KEY_LENGTH =
13
OA_BEACON_KEY =
"beacon".freeze
OA_ERROR_BEACON_KEY =
"errorBeacon".freeze
OA_LICENSE_KEY_KEY =
"licenseKey".freeze
OA_APPLICATIONID_KEY =
"applicationID".freeze
OA_TRANSACTION_NAME_KEY =
"transactionName".freeze
OA_QUEUE_TIME_KEY =
"queueTime".freeze
OA_APPLICATION_TIME_KEY =
"applicationTime".freeze
OA_AGENT_KEY =
"agent".freeze
OA_USER_ATTRIBUTES_KEY =
"userAttributes".freeze
OA_SSL_FOR_HTTP_KEY =
"sslForHttp".freeze

Instance Method Summary collapse

Methods included from Coerce

#event_params, #float, #int, #int_or_nil, #log_failure, #string

Constructor Details

#initialize(event_listener) ⇒ JavascriptInstrumentor

Returns a new instance of JavascriptInstrumentor.



14
15
16
# File 'lib/one_apm/agent/javascript_instrumentor.rb', line 14

def initialize(event_listener)
  event_listener.subscribe(:finished_configuring, &method(:log_configuration))
end

Instance Method Details

#add_ssl_for_http(data) ⇒ Object



156
157
158
159
160
161
# File 'lib/one_apm/agent/javascript_instrumentor.rb', line 156

def add_ssl_for_http(data)
  ssl_for_http = OneApm::Manager.config[:'browser_monitoring.ssl_for_http']
  unless ssl_for_http.nil?
    data[OA_SSL_FOR_HTTP_KEY] = ssl_for_http
  end
end

#add_user_attributes(data, txn) ⇒ Object



163
164
165
166
167
168
169
# File 'lib/one_apm/agent/javascript_instrumentor.rb', line 163

def add_user_attributes(data, txn)
  return unless include_custom_parameters?(txn)

  params = event_params(txn.custom_parameters)
  json = OneApm::JSONWrapper.dump(params)
  data[OA_USER_ATTRIBUTES_KEY] = obfuscator.obfuscate(json)
end

#browser_timing_config(state) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/one_apm/agent/javascript_instrumentor.rb', line 111

def browser_timing_config(state)
  txn = state.current_transaction
  return '' if txn.nil?

  txn.freeze_name_and_execute_if_not_ignored do
    data = data_for_js_agent(state)
    json = OneApm::JSONWrapper.dump(data)
    return html_safe_if_needed("\n<script type=\"text/javascript\">window.BWEUM||(BWEUM={});BWEUM.info=#{json}</script>")
  end

  ''
end

#browser_timing_headerObject



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/one_apm/agent/javascript_instrumentor.rb', line 87

def browser_timing_header
  return '' unless js_enabled_and_ready? # fast exit

  state = OneApm::TransactionState.tl_get

  return '' unless insert_js?(state) # slower exit

  bt_config = browser_timing_config(state)
  return '' if bt_config.empty?

  bt_config + browser_timing_loader
rescue => e
  OneApm::Manager.logger.debug "Failure during RUM browser_timing_header construction", e
  ''
end

#browser_timing_loaderObject



103
104
105
106
107
108
109
# File 'lib/one_apm/agent/javascript_instrumentor.rb', line 103

def browser_timing_loader
  if Manager.config[:'browser_monitoring.is_js_text']
    html_safe_if_needed("\n<script type=\"text/javascript\">#{Manager.config[:js_agent_loader]}</script>")
  else
    html_safe_if_needed("\n<script type=\"text/javascript\" src=\"#{Manager.config[:js_agent_loader]}\"></script>")
  end
end

#data_for_js_agent(state) ⇒ Object

NOTE: Internal prototyping may override this, so leave name stable!



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/one_apm/agent/javascript_instrumentor.rb', line 136

def data_for_js_agent(state)
  timings = state.timings

  data = {
    OA_BEACON_KEY           => OneApm::Manager.config[:beacon],
    OA_ERROR_BEACON_KEY     => OneApm::Manager.config[:error_beacon],
    OA_LICENSE_KEY_KEY      => OneApm::Manager.config[:browser_key],
    OA_APPLICATIONID_KEY    => OneApm::Manager.config[:application_id],
    OA_TRANSACTION_NAME_KEY => obfuscator.obfuscate(timings.transaction_name_or_unknown),
    OA_QUEUE_TIME_KEY       => timings.queue_time_in_millis,
    OA_APPLICATION_TIME_KEY => timings.app_time_in_millis,
    OA_AGENT_KEY            => OneApm::Manager.config[:js_agent_file]
  }

  add_ssl_for_http(data)
  add_user_attributes(data, state.current_transaction)

  data
end

#enabled?Boolean

Returns:

  • (Boolean)


28
29
30
# File 'lib/one_apm/agent/javascript_instrumentor.rb', line 28

def enabled?
  OneApm::Manager.config[:'rum.enabled'] && !!Manager.config[:beacon]
end

#has_custom_parameters?(txn) ⇒ Boolean

Returns:

  • (Boolean)


175
176
177
# File 'lib/one_apm/agent/javascript_instrumentor.rb', line 175

def has_custom_parameters?(txn)
  txn && txn.custom_parameters && !txn.custom_parameters.empty?
end

#html_safe_if_needed(string) ⇒ Object



179
180
181
182
# File 'lib/one_apm/agent/javascript_instrumentor.rb', line 179

def html_safe_if_needed(string)
  string = string.html_safe if string.respond_to?(:html_safe)
  string
end

#include_custom_parameters?(txn) ⇒ Boolean

Returns:

  • (Boolean)


171
172
173
# File 'lib/one_apm/agent/javascript_instrumentor.rb', line 171

def include_custom_parameters?(txn)
  has_custom_parameters?(txn) && OneApm::Manager.config[:'browser_monitoring.capture_attributes']
end

#insert_js?(state) ⇒ Boolean

Returns:

  • (Boolean)


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/one_apm/agent/javascript_instrumentor.rb', line 61

def insert_js?(state)
  if !state.current_transaction
    OneApm::Manager.logger.debug "Not in transaction. Skipping browser instrumentation."
    false
  elsif !state.is_transaction_traced?
    OneApm::Manager.logger.debug "Transaction is not traced. Skipping browser instrumentation."
    false
  elsif !state.is_execution_traced?
    OneApm::Manager.logger.debug "Execution is not traced. Skipping browser instrumentation."
    false
  elsif state.current_transaction.ignore_enduser?
    OneApm::Manager.logger.debug "Ignore end user for this transaction is set. Skipping browser instrumentation."
    false
  else
    true
  end
rescue => e
  OneApm::Manager.logger.debug "Failure during insert_js", e
  false
end

#js_enabled_and_ready?Boolean

Returns:

  • (Boolean)


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/one_apm/agent/javascript_instrumentor.rb', line 36

def js_enabled_and_ready?
  if !enabled?
    OneApm::Manager.logger.log_once(:debug, :js_agent_disabled,
                                      "JS agent instrumentation is disabled.")
    false
  elsif missing_config?(:js_agent_loader)
    OneApm::Manager.logger.log_once(:debug, :missing_js_agent_loader,
                                      "Missing :js_agent_loader. Skipping browser instrumentation.")
    false
  elsif missing_config?(:beacon)
    OneApm::Manager.logger.log_once(:debug, :missing_beacon,
                                      "Beacon configuration not received (yet?). Skipping browser instrumentation.")
    false
  elsif missing_config?(:browser_key)
    OneApm::Manager.logger.log_once(:debug, :missing_browser_key,
                                      "Browser key is not set. Skipping browser instrumentation.")
    false
  else
    true
  end
rescue => e
  OneApm::Manager.logger.debug "Failure during 'js_enabled_and_ready?'", e
  false
end

#log_configurationObject



18
19
20
21
22
23
24
25
26
# File 'lib/one_apm/agent/javascript_instrumentor.rb', line 18

def log_configuration
  OneApm::Manager.logger.debug("JS agent loader requested: #{OneApm::Manager.config[:'browser_monitoring.loader']}",
                               "JS agent loader debug: #{OneApm::Manager.config[:'browser_monitoring.debug']}",
                               "JS agent loader version: #{OneApm::Manager.config[:'browser_monitoring.loader_version']}")

  if !OneApm::Manager.config[:'rum.enabled']
    OneApm::Manager.logger.debug("Real User Monitoring is disabled for this agent. Edit your configuration to change this.")
  end
end

#missing_config?(key) ⇒ Boolean

Returns:

  • (Boolean)


82
83
84
85
# File 'lib/one_apm/agent/javascript_instrumentor.rb', line 82

def missing_config?(key)
  value = OneApm::Manager.config[key]
  value.nil? || value.empty?
end

#obfuscatorObject



32
33
34
# File 'lib/one_apm/agent/javascript_instrumentor.rb', line 32

def obfuscator
  @obfuscator ||= OneApm::Agent::Obfuscator.new(OneApm::Manager.config[:license_key], OA_RUM_KEY_LENGTH)
end