oneapm_rpm 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +30 -0
  3. data/.rubocop.yml +725 -0
  4. data/Gemfile +3 -0
  5. data/Guardfile +7 -0
  6. data/LICENSE +1 -0
  7. data/README.md +3 -0
  8. data/config/cert/cacert.pem +1177 -0
  9. data/config/database.yml +5 -0
  10. data/lib/initializers/goliath.rb +11 -0
  11. data/lib/initializers/other.rb +1 -0
  12. data/lib/initializers/rails.rb +15 -0
  13. data/lib/one_apm/agent.rb +253 -0
  14. data/lib/one_apm/agent/agent.rb +283 -0
  15. data/lib/one_apm/agent/agent/connect.rb +175 -0
  16. data/lib/one_apm/agent/agent/container_data_manager.rb +218 -0
  17. data/lib/one_apm/agent/agent/forkable_dispatcher_functions.rb +96 -0
  18. data/lib/one_apm/agent/agent/helpers.rb +45 -0
  19. data/lib/one_apm/agent/agent/start.rb +226 -0
  20. data/lib/one_apm/agent/agent/start_worker_thread.rb +148 -0
  21. data/lib/one_apm/agent/busy_calculator.rb +115 -0
  22. data/lib/one_apm/agent/cross_app/cross_app_monitor.rb +181 -0
  23. data/lib/one_apm/agent/cross_app/cross_app_tracing.rb +336 -0
  24. data/lib/one_apm/agent/database.rb +308 -0
  25. data/lib/one_apm/agent/database/active_record_helper.rb +80 -0
  26. data/lib/one_apm/agent/database/obfuscation_helpers.rb +76 -0
  27. data/lib/one_apm/agent/database/obfuscator.rb +78 -0
  28. data/lib/one_apm/agent/database/postgres_explain_obfuscator.rb +45 -0
  29. data/lib/one_apm/agent/datastores.rb +175 -0
  30. data/lib/one_apm/agent/datastores/metric_helper.rb +83 -0
  31. data/lib/one_apm/agent/datastores/mongo.rb +27 -0
  32. data/lib/one_apm/agent/datastores/mongo/metric_translator.rb +189 -0
  33. data/lib/one_apm/agent/datastores/mongo/obfuscator.rb +37 -0
  34. data/lib/one_apm/agent/datastores/mongo/statement_formatter.rb +51 -0
  35. data/lib/one_apm/agent/event/event_listener.rb +40 -0
  36. data/lib/one_apm/agent/event/event_loop.rb +191 -0
  37. data/lib/one_apm/agent/event/worker_loop.rb +97 -0
  38. data/lib/one_apm/agent/harvester.rb +48 -0
  39. data/lib/one_apm/agent/inbound_request_monitor.rb +30 -0
  40. data/lib/one_apm/agent/javascript_instrumentor.rb +186 -0
  41. data/lib/one_apm/agent/pipe/pipe_channel_manager.rb +275 -0
  42. data/lib/one_apm/agent/pipe/pipe_service.rb +81 -0
  43. data/lib/one_apm/agent/sampler.rb +55 -0
  44. data/lib/one_apm/agent/sampler_collection.rb +65 -0
  45. data/lib/one_apm/agent/samplers/cpu_sampler.rb +49 -0
  46. data/lib/one_apm/agent/samplers/delayed_job_sampler.rb +109 -0
  47. data/lib/one_apm/agent/samplers/memory_sampler.rb +144 -0
  48. data/lib/one_apm/agent/samplers/object_sampler.rb +22 -0
  49. data/lib/one_apm/agent/samplers/vm_sampler.rb +124 -0
  50. data/lib/one_apm/agent/synthetics_monitor.rb +48 -0
  51. data/lib/one_apm/agent/threading/agent_thread.rb +74 -0
  52. data/lib/one_apm/agent/threading/backtrace_node.rb +133 -0
  53. data/lib/one_apm/agent/threading/backtrace_service.rb +259 -0
  54. data/lib/one_apm/agent/threading/thread_profile.rb +155 -0
  55. data/lib/one_apm/collector/collector/helper.rb +139 -0
  56. data/lib/one_apm/collector/collector/http_connection.rb +254 -0
  57. data/lib/one_apm/collector/collector/server_methods.rb +71 -0
  58. data/lib/one_apm/collector/collector_service.rb +123 -0
  59. data/lib/one_apm/collector/commands/agent_command.rb +17 -0
  60. data/lib/one_apm/collector/commands/thread_profiler_session.rb +108 -0
  61. data/lib/one_apm/collector/commands/xray_session.rb +53 -0
  62. data/lib/one_apm/collector/commands/xray_session_collection.rb +156 -0
  63. data/lib/one_apm/collector/containers/agent_command_router.rb +153 -0
  64. data/lib/one_apm/collector/containers/custom_event_aggregator.rb +94 -0
  65. data/lib/one_apm/collector/containers/error_collector.rb +349 -0
  66. data/lib/one_apm/collector/containers/sql_sampler.rb +331 -0
  67. data/lib/one_apm/collector/containers/stats_engine.rb +34 -0
  68. data/lib/one_apm/collector/containers/transaction_event_aggregator.rb +249 -0
  69. data/lib/one_apm/collector/containers/transaction_sampler.rb +352 -0
  70. data/lib/one_apm/collector/containers/utilization_data.rb +36 -0
  71. data/lib/one_apm/collector/stats_engine/gc_profiler.rb +106 -0
  72. data/lib/one_apm/collector/stats_engine/metric_stats.rb +243 -0
  73. data/lib/one_apm/collector/stats_engine/stats_hash.rb +105 -0
  74. data/lib/one_apm/configuration.rb +429 -0
  75. data/lib/one_apm/configuration/autostart.rb +41 -0
  76. data/lib/one_apm/configuration/default_source.rb +1026 -0
  77. data/lib/one_apm/configuration/environment_source.rb +113 -0
  78. data/lib/one_apm/configuration/high_security_source.rb +56 -0
  79. data/lib/one_apm/configuration/manual_source.rb +13 -0
  80. data/lib/one_apm/configuration/server_source.rb +60 -0
  81. data/lib/one_apm/configuration/yaml_source.rb +134 -0
  82. data/lib/one_apm/errors/agent_errors.rb +26 -0
  83. data/lib/one_apm/errors/internal_agent_error.rb +16 -0
  84. data/lib/one_apm/errors/noticed_error.rb +79 -0
  85. data/lib/one_apm/frameworks/external.rb +15 -0
  86. data/lib/one_apm/frameworks/rails.rb +103 -0
  87. data/lib/one_apm/frameworks/rails3.rb +37 -0
  88. data/lib/one_apm/frameworks/rails4.rb +21 -0
  89. data/lib/one_apm/frameworks/ruby.rb +21 -0
  90. data/lib/one_apm/frameworks/sinatra.rb +12 -0
  91. data/lib/one_apm/inst/3rd/active_merchant.rb +35 -0
  92. data/lib/one_apm/inst/3rd/acts_as_solr.rb +70 -0
  93. data/lib/one_apm/inst/3rd/authlogic.rb +23 -0
  94. data/lib/one_apm/inst/3rd/sunspot.rb +31 -0
  95. data/lib/one_apm/inst/background_job/active_job.rb +88 -0
  96. data/lib/one_apm/inst/background_job/delayed_job.rb +52 -0
  97. data/lib/one_apm/inst/background_job/delayed_job_injection.rb +8 -0
  98. data/lib/one_apm/inst/background_job/resque.rb +107 -0
  99. data/lib/one_apm/inst/background_job/sidekiq.rb +64 -0
  100. data/lib/one_apm/inst/dispatcher/passenger.rb +25 -0
  101. data/lib/one_apm/inst/dispatcher/rainbows.rb +23 -0
  102. data/lib/one_apm/inst/framework/grape.rb +94 -0
  103. data/lib/one_apm/inst/framework/padrino.rb +30 -0
  104. data/lib/one_apm/inst/framework/sinatra.rb +185 -0
  105. data/lib/one_apm/inst/framework/sinatra/ignorer.rb +50 -0
  106. data/lib/one_apm/inst/framework/sinatra/transaction_namer.rb +54 -0
  107. data/lib/one_apm/inst/http_clients/curb.rb +189 -0
  108. data/lib/one_apm/inst/http_clients/excon.rb +70 -0
  109. data/lib/one_apm/inst/http_clients/excon/connection.rb +31 -0
  110. data/lib/one_apm/inst/http_clients/excon/middleware.rb +55 -0
  111. data/lib/one_apm/inst/http_clients/httpclient.rb +44 -0
  112. data/lib/one_apm/inst/http_clients/net.rb +34 -0
  113. data/lib/one_apm/inst/http_clients/typhoeus.rb +76 -0
  114. data/lib/one_apm/inst/nosql/memcache.rb +134 -0
  115. data/lib/one_apm/inst/nosql/mongo.rb +126 -0
  116. data/lib/one_apm/inst/nosql/mongo_moped.rb +85 -0
  117. data/lib/one_apm/inst/nosql/redis.rb +83 -0
  118. data/lib/one_apm/inst/orm/active_record.rb +99 -0
  119. data/lib/one_apm/inst/orm/active_record_4.rb +28 -0
  120. data/lib/one_apm/inst/orm/data_mapper.rb +180 -0
  121. data/lib/one_apm/inst/orm/sequel.rb +47 -0
  122. data/lib/one_apm/inst/rack.rb +38 -0
  123. data/lib/one_apm/inst/rack/rack.rb +44 -0
  124. data/lib/one_apm/inst/rack/rack_builder.rb +51 -0
  125. data/lib/one_apm/inst/rails/action_controller.rb +118 -0
  126. data/lib/one_apm/inst/rails/action_web_service.rb +44 -0
  127. data/lib/one_apm/inst/rails/errors.rb +43 -0
  128. data/lib/one_apm/inst/rails3/action_controller.rb +172 -0
  129. data/lib/one_apm/inst/rails3/errors.rb +43 -0
  130. data/lib/one_apm/inst/rails4/action_controller.rb +27 -0
  131. data/lib/one_apm/inst/rails4/action_controller_subscriber.rb +121 -0
  132. data/lib/one_apm/inst/rails4/action_view.rb +23 -0
  133. data/lib/one_apm/inst/rails4/action_view_subscriber.rb +93 -0
  134. data/lib/one_apm/inst/rails4/active_record_subscriber.rb +96 -0
  135. data/lib/one_apm/inst/rails4/errors.rb +42 -0
  136. data/lib/one_apm/inst/rails_middleware.rb +40 -0
  137. data/lib/one_apm/inst/support/evented_subscriber.rb +98 -0
  138. data/lib/one_apm/inst/support/ignore_actions.rb +39 -0
  139. data/lib/one_apm/inst/support/queue_time.rb +76 -0
  140. data/lib/one_apm/inst/transaction_base.rb +405 -0
  141. data/lib/one_apm/logger/agent_logger.rb +206 -0
  142. data/lib/one_apm/logger/audit_logger.rb +78 -0
  143. data/lib/one_apm/logger/memory_logger.rb +50 -0
  144. data/lib/one_apm/logger/null_logger.rb +19 -0
  145. data/lib/one_apm/metrics/metric_data.rb +72 -0
  146. data/lib/one_apm/metrics/metric_spec.rb +82 -0
  147. data/lib/one_apm/metrics/stats.rb +173 -0
  148. data/lib/one_apm/probe.rb +16 -0
  149. data/lib/one_apm/probe/framework_loader.rb +53 -0
  150. data/lib/one_apm/probe/instance_methods.rb +105 -0
  151. data/lib/one_apm/probe/instrumentation.rb +60 -0
  152. data/lib/one_apm/rack/browser_monitoring.rb +144 -0
  153. data/lib/one_apm/rack/middleware_base.rb +27 -0
  154. data/lib/one_apm/rack/middleware_hooks.rb +17 -0
  155. data/lib/one_apm/rack/middleware_tracing.rb +81 -0
  156. data/lib/one_apm/rack/middleware_wrapper.rb +86 -0
  157. data/lib/one_apm/support/chained_call.rb +15 -0
  158. data/lib/one_apm/support/coerce.rb +81 -0
  159. data/lib/one_apm/support/collection_helper.rb +79 -0
  160. data/lib/one_apm/support/dotted_hash.rb +45 -0
  161. data/lib/one_apm/support/encoders.rb +34 -0
  162. data/lib/one_apm/support/environment_report.rb +127 -0
  163. data/lib/one_apm/support/event_buffer.rb +82 -0
  164. data/lib/one_apm/support/event_buffer/sampled_buffer.rb +45 -0
  165. data/lib/one_apm/support/event_buffer/sized_buffer.rb +21 -0
  166. data/lib/one_apm/support/event_buffer/synthetics_event_buffer.rb +40 -0
  167. data/lib/one_apm/support/helper.rb +49 -0
  168. data/lib/one_apm/support/hostname.rb +13 -0
  169. data/lib/one_apm/support/http_clients/curb_wrappers.rb +65 -0
  170. data/lib/one_apm/support/http_clients/excon_wrappers.rb +63 -0
  171. data/lib/one_apm/support/http_clients/httpclient_wrappers.rb +61 -0
  172. data/lib/one_apm/support/http_clients/net_http_wrappers.rb +48 -0
  173. data/lib/one_apm/support/http_clients/typhoeus_wrappers.rb +73 -0
  174. data/lib/one_apm/support/http_clients/uri_util.rb +39 -0
  175. data/lib/one_apm/support/json_marshaller.rb +68 -0
  176. data/lib/one_apm/support/json_wrapper.rb +130 -0
  177. data/lib/one_apm/support/language_support.rb +142 -0
  178. data/lib/one_apm/support/library_detection.rb +119 -0
  179. data/lib/one_apm/support/local_environment.rb +196 -0
  180. data/lib/one_apm/support/marshaller.rb +62 -0
  181. data/lib/one_apm/support/method_tracer.rb +334 -0
  182. data/lib/one_apm/support/method_tracer/helpers.rb +92 -0
  183. data/lib/one_apm/support/method_tracer/traced_method_stack.rb +103 -0
  184. data/lib/one_apm/support/obfuscator.rb +47 -0
  185. data/lib/one_apm/support/okjson.rb +601 -0
  186. data/lib/one_apm/support/parameter_filtering.rb +35 -0
  187. data/lib/one_apm/support/rules_engine.rb +56 -0
  188. data/lib/one_apm/support/rules_engine/replacement_rule.rb +80 -0
  189. data/lib/one_apm/support/rules_engine/segment_terms_rule.rb +46 -0
  190. data/lib/one_apm/support/server.rb +11 -0
  191. data/lib/one_apm/support/supported_versions.rb +257 -0
  192. data/lib/one_apm/support/system_info.rb +211 -0
  193. data/lib/one_apm/support/timer_lib.rb +29 -0
  194. data/lib/one_apm/support/version_number.rb +51 -0
  195. data/lib/one_apm/support/vm.rb +30 -0
  196. data/lib/one_apm/support/vm/jruby_vm.rb +38 -0
  197. data/lib/one_apm/support/vm/monotonic_gc_profiler.rb +43 -0
  198. data/lib/one_apm/support/vm/mri_vm.rb +85 -0
  199. data/lib/one_apm/support/vm/rubinius_vm.rb +129 -0
  200. data/lib/one_apm/support/vm/snapshot.rb +18 -0
  201. data/lib/one_apm/transaction.rb +336 -0
  202. data/lib/one_apm/transaction/class_methods.rb +132 -0
  203. data/lib/one_apm/transaction/instance_helpers.rb +82 -0
  204. data/lib/one_apm/transaction/metric_constants.rb +42 -0
  205. data/lib/one_apm/transaction/sample_buffer/force_persist_sample_buffer.rb +21 -0
  206. data/lib/one_apm/transaction/sample_buffer/slowest_sample_buffer.rb +21 -0
  207. data/lib/one_apm/transaction/sample_buffer/synthetics_sample_buffer.rb +21 -0
  208. data/lib/one_apm/transaction/sample_buffer/transaction_sample_buffer.rb +101 -0
  209. data/lib/one_apm/transaction/sample_buffer/xray_sample_buffer.rb +60 -0
  210. data/lib/one_apm/transaction/segment.rb +193 -0
  211. data/lib/one_apm/transaction/segment_summary.rb +51 -0
  212. data/lib/one_apm/transaction/thread_local_access.rb +73 -0
  213. data/lib/one_apm/transaction/transaction_analysis.rb +78 -0
  214. data/lib/one_apm/transaction/transaction_apdex.rb +20 -0
  215. data/lib/one_apm/transaction/transaction_cpu.rb +22 -0
  216. data/lib/one_apm/transaction/transaction_finish_append.rb +67 -0
  217. data/lib/one_apm/transaction/transaction_ignore.rb +33 -0
  218. data/lib/one_apm/transaction/transaction_jruby_functions.rb +40 -0
  219. data/lib/one_apm/transaction/transaction_metrics.rb +53 -0
  220. data/lib/one_apm/transaction/transaction_name.rb +90 -0
  221. data/lib/one_apm/transaction/transaction_namer.rb +49 -0
  222. data/lib/one_apm/transaction/transaction_sample.rb +204 -0
  223. data/lib/one_apm/transaction/transaction_sample_builder.rb +168 -0
  224. data/lib/one_apm/transaction/transaction_state.rb +149 -0
  225. data/lib/one_apm/transaction/transaction_summary.rb +28 -0
  226. data/lib/one_apm/transaction/transaction_synthetics.rb +40 -0
  227. data/lib/one_apm/transaction/transaction_timings.rb +54 -0
  228. data/lib/one_apm/version.rb +13 -0
  229. data/lib/oneapm_rpm.rb +16 -0
  230. data/lib/sequel/extensions/oneapm_instrumentation.rb +84 -0
  231. data/lib/sequel/plugins/oneapm_instrumentation.rb +66 -0
  232. data/oneapm.yml +135 -0
  233. data/oneapm_rpm.gemspec +58 -0
  234. metadata +474 -0
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ module OneApm
4
+ module Agent
5
+ class InboundRequestMonitor
6
+
7
+ attr_reader :obfuscator
8
+
9
+ def initialize(events)
10
+ events.subscribe(:finished_configuring) do
11
+ setup_obfuscator
12
+ on_finished_configuring(events)
13
+ end
14
+ end
15
+
16
+ def setup_obfuscator
17
+ @obfuscator = OneApm::Agent::Obfuscator.new(OneApm::Agent.config[:encoding_key])
18
+ end
19
+
20
+ def deserialize_header(encoded_header, key)
21
+ decoded_header = obfuscator.deobfuscate(encoded_header)
22
+ OneApm::JSONWrapper.load(decoded_header)
23
+ rescue => err
24
+ OneApm::Agent.logger.debug("Failure deserializing encoded header '#{key}' in #{self.class}, #{err.class}, #{err.message}")
25
+ nil
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,186 @@
1
+ # encoding: utf-8
2
+
3
+ require 'base64'
4
+ require 'one_apm/support/obfuscator'
5
+ require 'one_apm/transaction/transaction_timings'
6
+
7
+ module OneApm
8
+ module Agent
9
+ class JavascriptInstrumentor
10
+ include OneApm::Coerce
11
+
12
+ RUM_KEY_LENGTH = 13
13
+
14
+ def initialize(event_listener)
15
+ event_listener.subscribe(:finished_configuring, &method(:log_configuration))
16
+ end
17
+
18
+ def log_configuration
19
+ OneApm::Agent.logger.debug("JS agent loader requested: #{OneApm::Agent.config[:'browser_monitoring.loader']}",
20
+ "JS agent loader debug: #{OneApm::Agent.config[:'browser_monitoring.debug']}",
21
+ "JS agent loader version: #{OneApm::Agent.config[:'browser_monitoring.loader_version']}")
22
+
23
+ if !OneApm::Agent.config[:'rum.enabled']
24
+ OneApm::Agent.logger.debug("Real User Monitoring is disabled for this agent. Edit your configuration to change this.")
25
+ end
26
+ end
27
+
28
+ def enabled?
29
+ Agent.config[:'rum.enabled'] && !!Agent.config[:beacon]
30
+ end
31
+
32
+ def obfuscator
33
+ @obfuscator ||= OneApm::Agent::Obfuscator.new(OneApm::Agent.config[:license_key], RUM_KEY_LENGTH)
34
+ end
35
+
36
+ def js_enabled_and_ready?
37
+ if !enabled?
38
+ ::OneApm::Agent.logger.log_once(:debug, :js_agent_disabled,
39
+ "JS agent instrumentation is disabled.")
40
+ false
41
+ elsif missing_config?(:js_agent_loader)
42
+ ::OneApm::Agent.logger.log_once(:debug, :missing_js_agent_loader,
43
+ "Missing :js_agent_loader. Skipping browser instrumentation.")
44
+ false
45
+ elsif missing_config?(:beacon)
46
+ ::OneApm::Agent.logger.log_once(:debug, :missing_beacon,
47
+ "Beacon configuration not received (yet?). Skipping browser instrumentation.")
48
+ false
49
+ elsif missing_config?(:browser_key)
50
+ ::OneApm::Agent.logger.log_once(:debug, :missing_browser_key,
51
+ "Browser key is not set. Skipping browser instrumentation.")
52
+ false
53
+ else
54
+ true
55
+ end
56
+ rescue => e
57
+ ::OneApm::Agent.logger.debug "Failure during 'js_enabled_and_ready?'", e
58
+ false
59
+ end
60
+
61
+ def insert_js?(state)
62
+ if !state.current_transaction
63
+ ::OneApm::Agent.logger.debug "Not in transaction. Skipping browser instrumentation."
64
+ false
65
+ elsif !state.is_transaction_traced?
66
+ ::OneApm::Agent.logger.debug "Transaction is not traced. Skipping browser instrumentation."
67
+ false
68
+ elsif !state.is_execution_traced?
69
+ ::OneApm::Agent.logger.debug "Execution is not traced. Skipping browser instrumentation."
70
+ false
71
+ elsif state.current_transaction.ignore_enduser?
72
+ ::OneApm::Agent.logger.debug "Ignore end user for this transaction is set. Skipping browser instrumentation."
73
+ false
74
+ else
75
+ true
76
+ end
77
+ rescue => e
78
+ ::OneApm::Agent.logger.debug "Failure during insert_js", e
79
+ false
80
+ end
81
+
82
+ def missing_config?(key)
83
+ value = OneApm::Agent.config[key]
84
+ value.nil? || value.empty?
85
+ end
86
+
87
+ def browser_timing_header #THREAD_LOCAL_ACCESS
88
+ return '' unless js_enabled_and_ready? # fast exit
89
+
90
+ state = OneApm::TransactionState.tl_get
91
+
92
+ return '' unless insert_js?(state) # slower exit
93
+
94
+ bt_config = browser_timing_config(state)
95
+ return '' if bt_config.empty?
96
+
97
+ bt_config + browser_timing_loader
98
+ rescue => e
99
+ ::OneApm::Agent.logger.debug "Failure during RUM browser_timing_header construction", e
100
+ ''
101
+ end
102
+
103
+ def browser_timing_loader
104
+ html_safe_if_needed("\n<script type=\"text/javascript\" src=\"#{Agent.config[:js_agent_loader]}\"></script>")
105
+ end
106
+
107
+ def browser_timing_config(state)
108
+ txn = state.current_transaction
109
+ return '' if txn.nil?
110
+
111
+ txn.freeze_name_and_execute_if_not_ignored do
112
+ data = data_for_js_agent(state)
113
+ json = OneApm::JSONWrapper.dump(data)
114
+ return html_safe_if_needed("\n<script type=\"text/javascript\">window.BWEUM||(BWEUM={});BWEUM.info=#{json}</script>")
115
+ end
116
+
117
+ ''
118
+ end
119
+
120
+ BEACON_KEY = "beacon".freeze
121
+ ERROR_BEACON_KEY = "errorBeacon".freeze
122
+ LICENSE_KEY_KEY = "licenseKey".freeze
123
+ APPLICATIONID_KEY = "applicationID".freeze
124
+ TRANSACTION_NAME_KEY = "transactionName".freeze
125
+ QUEUE_TIME_KEY = "queueTime".freeze
126
+ APPLICATION_TIME_KEY = "applicationTime".freeze
127
+ AGENT_KEY = "agent".freeze
128
+ USER_ATTRIBUTES_KEY = "userAttributes".freeze
129
+ SSL_FOR_HTTP_KEY = "sslForHttp".freeze
130
+
131
+ # NOTE: Internal prototyping may override this, so leave name stable!
132
+ def data_for_js_agent(state)
133
+ timings = state.timings
134
+
135
+ data = {
136
+ BEACON_KEY => OneApm::Agent.config[:beacon],
137
+ ERROR_BEACON_KEY => OneApm::Agent.config[:error_beacon],
138
+ LICENSE_KEY_KEY => OneApm::Agent.config[:browser_key],
139
+ APPLICATIONID_KEY => OneApm::Agent.config[:application_id],
140
+ TRANSACTION_NAME_KEY => obfuscator.obfuscate(timings.transaction_name_or_unknown),
141
+ QUEUE_TIME_KEY => timings.queue_time_in_millis,
142
+ APPLICATION_TIME_KEY => timings.app_time_in_millis,
143
+ AGENT_KEY => OneApm::Agent.config[:js_agent_file]
144
+ }
145
+
146
+ add_ssl_for_http(data)
147
+ add_user_attributes(data, state.current_transaction)
148
+
149
+ data
150
+ end
151
+
152
+ def add_ssl_for_http(data)
153
+ ssl_for_http = OneApm::Agent.config[:'browser_monitoring.ssl_for_http']
154
+ unless ssl_for_http.nil?
155
+ data[SSL_FOR_HTTP_KEY] = ssl_for_http
156
+ end
157
+ end
158
+
159
+ def add_user_attributes(data, txn)
160
+ return unless include_custom_parameters?(txn)
161
+
162
+ params = event_params(txn.custom_parameters)
163
+ json = OneApm::JSONWrapper.dump(params)
164
+ data[USER_ATTRIBUTES_KEY] = obfuscator.obfuscate(json)
165
+ end
166
+
167
+ # Still support deprecated capture_attributes.page_view_events for
168
+ # clients that use it. Could potentially be removed if we don't have
169
+ # anymore users with it set according to zeitgeist.
170
+ def include_custom_parameters?(txn)
171
+ has_custom_parameters?(txn) &&
172
+ (OneApm::Agent.config[:'browser_monitoring.capture_attributes'] ||
173
+ OneApm::Agent.config[:'capture_attributes.page_view_events'])
174
+ end
175
+
176
+ def has_custom_parameters?(txn)
177
+ txn && txn.custom_parameters && !txn.custom_parameters.empty?
178
+ end
179
+
180
+ def html_safe_if_needed(string)
181
+ string = string.html_safe if string.respond_to?(:html_safe)
182
+ string
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,275 @@
1
+ # encoding: utf-8
2
+
3
+ require 'base64'
4
+
5
+ module OneApm
6
+ module Agent
7
+
8
+ #--
9
+ # Manages the registering and servicing of pipes used by child
10
+ # processes to report data to their parent, rather than directly
11
+ # to the collector.
12
+ module PipeChannelManager
13
+ extend self
14
+
15
+ def register_report_channel(id)
16
+ listener.register_pipe(id)
17
+ end
18
+
19
+ def channels
20
+ listener.pipes
21
+ end
22
+
23
+ def listener
24
+ @listener ||= Listener.new
25
+ end
26
+
27
+ # Expected initial sequence of events for Pipe usage:
28
+ #
29
+ # 1. Pipe is created in parent process (read and write ends open)
30
+ # 2. Parent process forks
31
+ # 3. An after_fork hook is invoked in the child
32
+ # 4. From after_fork hook, child closes read end of pipe, and
33
+ # writes a ready marker on the pipe (after_fork_in_child).
34
+ # 5. The parent receives the ready marker, and closes the write end of the
35
+ # pipe in response (after_fork_in_parent).
36
+ #
37
+ # After this sequence of steps, an exit (whether clean or not) of the
38
+ # child will result in the pipe being marked readable again, and giving an
39
+ # EOF marker (nil) when read. Note that closing of the unused ends of the
40
+ # pipe in the parent and child processes is essential in order for the EOF
41
+ # to be correctly triggered. The ready marker mechanism is used because
42
+ # there's no easy hook for after_fork in the parent process.
43
+ #
44
+ # This class provides message framing (separation of individual messages),
45
+ # but not serialization. Serialization / deserialization is the
46
+ # responsibility of clients.
47
+ #
48
+ # Message framing works like this:
49
+ #
50
+ # Each message sent across the pipe is preceded by a length tag that
51
+ # specifies the length of the message that immediately follows, in bytes.
52
+ # The length tags are serialized as unsigned big-endian long values, (4
53
+ # bytes each). This means that the maximum theoretical message size is
54
+ # 4 GB - much larger than we'd ever need or want for this application.
55
+ #
56
+ class Pipe
57
+ READY_MARKER = "READY"
58
+ NUM_LENGTH_BYTES = 4
59
+
60
+ attr_accessor :in, :out
61
+ attr_reader :last_read, :parent_pid
62
+
63
+ def initialize
64
+ @out, @in = IO.pipe
65
+ if defined?(::Encoding::ASCII_8BIT)
66
+ @in.set_encoding(::Encoding::ASCII_8BIT)
67
+ end
68
+ @last_read = Time.now
69
+ @parent_pid = $$
70
+ end
71
+
72
+ def close
73
+ @out.close unless @out.closed?
74
+ @in.close unless @in.closed?
75
+ end
76
+
77
+ def serialize_message_length(data)
78
+ [data.bytesize].pack("L>")
79
+ end
80
+
81
+ def deserialize_message_length(data)
82
+ data.unpack("L>").first
83
+ end
84
+
85
+ def write(data)
86
+ @out.close unless @out.closed?
87
+ @in << serialize_message_length(data)
88
+ @in << data
89
+ end
90
+
91
+ def read
92
+ @in.close unless @in.closed?
93
+ @last_read = Time.now
94
+ length_bytes = @out.read(NUM_LENGTH_BYTES)
95
+ if length_bytes
96
+ message_length = deserialize_message_length(length_bytes)
97
+ if message_length
98
+ @out.read(message_length)
99
+ else
100
+ length_hex = length_bytes.bytes.map { |b| b.to_s(16) }.join(' ')
101
+ OneApm::Agent.logger.error("Failed to deserialize message length from pipe. Bytes: [#{length_hex}]")
102
+ nil
103
+ end
104
+ else
105
+ OneApm::Agent.logger.error("Failed to read bytes for length from pipe.")
106
+ nil
107
+ end
108
+ end
109
+
110
+ def eof?
111
+ !@out.closed? && @out.eof?
112
+ end
113
+
114
+ def after_fork_in_child
115
+ @out.close unless @out.closed?
116
+ write(READY_MARKER)
117
+ end
118
+
119
+ def after_fork_in_parent
120
+ @in.close unless @in.closed?
121
+ end
122
+
123
+ def closed?
124
+ @out.closed? && @in.closed?
125
+ end
126
+ end
127
+
128
+ class Listener
129
+ attr_reader :thread
130
+
131
+ # This attr_accessor intentionally provides unsynchronized access to the
132
+ # @pipes hash. It is used to look up the write end of the pipe from
133
+ # within the Resque child process, and must be unsynchronized in order
134
+ # to avoid a potential deadlock in which the PipeChannelManager::Listener
135
+ # thread in the parent process is holding the @pipes_lock at the time of
136
+ # the fork.
137
+ attr_accessor :pipes, :timeout, :select_timeout
138
+
139
+ def initialize
140
+ @pipes = {}
141
+ @pipes_lock = Mutex.new
142
+
143
+ @timeout = 360
144
+ @select_timeout = 60
145
+ end
146
+
147
+ def wakeup
148
+ wake.in << '.'
149
+ end
150
+
151
+ def register_pipe(id)
152
+ @pipes_lock.synchronize do
153
+ @pipes[id] = Pipe.new
154
+ end
155
+
156
+ wakeup
157
+ end
158
+
159
+ def start
160
+ return if @started == true
161
+ @started = true
162
+ @thread = OneApm::Agent::Threading::AgentThread.create('Pipe Channel Manager') do
163
+ now = nil
164
+ loop do
165
+ clean_up_pipes
166
+
167
+ pipes_to_listen_to = @pipes_lock.synchronize do
168
+ @pipes.values.map{|pipe| pipe.out} + [wake.out]
169
+ end
170
+
171
+ OneApm::Agent.record_metric('Supportability/Listeners',
172
+ (Time.now - now).to_f) if now
173
+
174
+ if ready = IO.select(pipes_to_listen_to, [], [], @select_timeout)
175
+ now = Time.now
176
+
177
+ ready_pipes = ready[0]
178
+ ready_pipes.each do |pipe|
179
+ merge_data_from_pipe(pipe) unless pipe == wake.out
180
+ end
181
+
182
+ wake.out.read(1) if ready_pipes.include?(wake.out)
183
+ end
184
+
185
+ break unless should_keep_listening?
186
+ end
187
+ end
188
+ sleep 0.001 # give time for the thread to spawn
189
+ end
190
+
191
+ def stop_listener_thread
192
+ @started = false
193
+ wakeup
194
+ @thread.join
195
+ end
196
+
197
+ def stop
198
+ return unless @started == true
199
+ stop_listener_thread
200
+ close_all_pipes
201
+ @wake.close
202
+ @wake = nil
203
+ end
204
+
205
+ def close_all_pipes
206
+ @pipes_lock.synchronize do
207
+ @pipes.each do |id, pipe|
208
+ pipe.close if pipe
209
+ end
210
+ @pipes = {}
211
+ end
212
+ end
213
+
214
+ def wake
215
+ @wake ||= Pipe.new
216
+ end
217
+
218
+ def started?
219
+ @started
220
+ end
221
+
222
+ protected
223
+
224
+ def merge_data_from_pipe(pipe_handle)
225
+ pipe = find_pipe_for_handle(pipe_handle)
226
+ raw_payload = pipe.read
227
+ if raw_payload && !raw_payload.empty?
228
+ if raw_payload == Pipe::READY_MARKER
229
+ pipe.after_fork_in_parent
230
+ else
231
+ payload = unmarshal(raw_payload)
232
+ if payload
233
+ endpoint, items = payload
234
+ OneApm::Agent.instance.merge_data_for_endpoint(endpoint, items)
235
+ end
236
+ end
237
+ end
238
+
239
+ pipe.close if pipe.eof?
240
+ end
241
+
242
+ def unmarshal(data)
243
+ OneApm::LanguageSupport.with_cautious_gc do
244
+ Marshal.load(data)
245
+ end
246
+ rescue StandardError => e
247
+ ::OneApm::Agent.logger.error "Failure unmarshalling message from Resque child process", e
248
+ ::OneApm::Agent.logger.debug Base64.encode64(data)
249
+ nil
250
+ end
251
+
252
+ def should_keep_listening?
253
+ @started || @pipes_lock.synchronize { @pipes.values.find{|pipe| !pipe.in.closed?} }
254
+ end
255
+
256
+ def clean_up_pipes
257
+ @pipes_lock.synchronize do
258
+ @pipes.values.each do |pipe|
259
+ if pipe.last_read.to_f + @timeout < Time.now.to_f
260
+ pipe.close unless pipe.closed?
261
+ end
262
+ end
263
+ @pipes.reject! {|id, pipe| pipe.out.closed? }
264
+ end
265
+ end
266
+
267
+ def find_pipe_for_handle(out_handle)
268
+ @pipes_lock.synchronize do
269
+ @pipes.values.find{|pipe| pipe.out == out_handle }
270
+ end
271
+ end
272
+ end
273
+ end
274
+ end
275
+ end