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,71 @@
1
+ # encoding: utf-8
2
+
3
+ require 'resolv'
4
+ require 'one_apm/support/server'
5
+
6
+ module OneApm
7
+ module Collector
8
+ class CollectorService
9
+ module ServerMethods
10
+
11
+ def server
12
+ @remote_server ||= server_from_host
13
+ end
14
+
15
+ # a new instances of the proxy server - this passes through if
16
+ # there is no proxy, otherwise it has proxy configuration
17
+ # information pulled from the config file
18
+ def proxy_server
19
+ @proxy_server ||= OneApm::Support::ProxyServer.new(Agent.config[:proxy_host],
20
+ Agent.config[:proxy_port],
21
+ Agent.config[:proxy_user],
22
+ Agent.config[:proxy_pass])
23
+ end
24
+
25
+ # turns a hostname into an ip address and returns a
26
+ # OneApm::Support::Server that contains the configuration info
27
+ def server_from_host(hostname=nil)
28
+ host = hostname || Agent.config[:host]
29
+
30
+ # if the host is not an IP address, turn it into one
31
+ OneApm::Support::Server.new(host, Agent.config[:port], convert_to_ip_address(host))
32
+ end
33
+
34
+ # Check to see if we need to look up the IP address
35
+ # If it's an IP address already, we pass it through.
36
+ # If it's nil, or localhost, we don't bother.
37
+ # Otherwise, use `resolve_ip_address` to find one
38
+ def convert_to_ip_address(host)
39
+ # here we leave it as a host name since the cert verification
40
+ # needs it in host form
41
+ return host if Agent.config[:ssl]
42
+ # We won't talk directly to the host, so no need to resolve if proxy configured
43
+ return host if Agent.config[:proxy_host]
44
+ return nil if host.nil? || host.downcase == "localhost"
45
+ ip = resolve_ip_address(host)
46
+
47
+ OneApm::Agent.logger.debug "Resolved #{host} to #{ip}"
48
+ ip
49
+ end
50
+
51
+ # Look up the ip address of the host using the pure ruby lookup
52
+ # to prevent blocking. If that fails, fall back to the regular
53
+ # IPSocket library. Return nil if we can't find the host ip
54
+ # address and don't have a good default.
55
+ def resolve_ip_address(host)
56
+ Resolv.getaddress(host)
57
+ rescue => e
58
+ OneApm::Agent.logger.warn("DNS Error caching IP address:", e)
59
+ begin
60
+ OneApm::Agent.logger.debug("Trying native DNS lookup since Resolv failed")
61
+ IPSocket.getaddress(host)
62
+ rescue => e
63
+ OneApm::Agent.logger.error("Could not look up server address: #{e}")
64
+ nil
65
+ end
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,123 @@
1
+ # encoding: utf-8
2
+
3
+ require 'zlib'
4
+ require 'one_apm/logger/audit_logger'
5
+ require 'one_apm/support/encoders'
6
+ require 'one_apm/support/marshaller'
7
+ require 'one_apm/support/json_marshaller'
8
+ require 'one_apm/collector/collector/server_methods'
9
+ require 'one_apm/collector/collector/http_connection'
10
+ require 'one_apm/collector/collector/helper'
11
+
12
+ module OneApm
13
+ module Collector
14
+ class CollectorService
15
+ include OneApm::Collector::CollectorService::Helper
16
+ include OneApm::Collector::CollectorService::ServerMethods
17
+ include OneApm::Collector::CollectorService::HttpConnection
18
+
19
+ PROTOCOL_VERSION = 1
20
+
21
+ attr_accessor :request_timeout, :agent_id
22
+ attr_reader :collector,:marshaller, :metric_id_cache
23
+
24
+ def initialize(license_key = nil, collector = nil)
25
+ @license_key = license_key || Agent.config[:license_key]
26
+ @collector = collector || server
27
+ @request_timeout = Agent.config[:timeout]
28
+ @metric_id_cache = {}
29
+ @audit_logger = ::OneApm::Agent::AuditLogger.new
30
+
31
+ Agent.config.register_callback(:'audit_log.enabled') do |enabled|
32
+ @audit_logger.enabled = enabled
33
+ end
34
+
35
+ Agent.config.register_callback(:ssl) do |ssl|
36
+ if !ssl
37
+ OneApm::Agent.logger.warn("Agent is configured not to use SSL when communicating with OneApm's servers")
38
+ else
39
+ OneApm::Agent.logger.debug("Agent is configured to use SSL")
40
+ end
41
+ end
42
+
43
+ Agent.config.register_callback(:marshaller) do |marshaller|
44
+ @marshaller = OneApm::Support::JsonMarshaller.new
45
+ end
46
+ end
47
+
48
+ def get_redirect_host
49
+ invoke_remote(:get_redirect_host)
50
+ end
51
+
52
+ def connect(settings={})
53
+ if host = get_redirect_host
54
+ @collector = server_from_host(host)
55
+ end
56
+ response = invoke_remote(:connect, [settings])
57
+ @agent_id = response['agent_run_id']
58
+ response
59
+ end
60
+
61
+ def shutdown(time)
62
+ invoke_remote(:shutdown, [@agent_id, time.to_i]) if @agent_id
63
+ end
64
+
65
+ def metric_data(stats_hash)
66
+ timeslice_start = stats_hash.started_at
67
+ timeslice_end = stats_hash.harvested_at || Time.now
68
+
69
+ metric_data_array = build_metric_data_array(stats_hash)
70
+
71
+ result = invoke_remote(
72
+ :metric_data,
73
+ [@agent_id, timeslice_start.to_f, timeslice_end.to_f, metric_data_array],
74
+ :item_count => metric_data_array.size
75
+ )
76
+
77
+ fill_metric_id_cache(result)
78
+ result
79
+ end
80
+
81
+ def error_data(unsent_errors)
82
+ invoke_remote(:error_data, [@agent_id, unsent_errors], :item_count => unsent_errors.size)
83
+ end
84
+
85
+ def transaction_sample_data(traces)
86
+ invoke_remote(:transaction_sample_data, [@agent_id, traces], :item_count => traces.size)
87
+ end
88
+
89
+ def sql_trace_data(sql_traces)
90
+ invoke_remote(:sql_trace_data, [sql_traces], :item_count => sql_traces.size)
91
+ end
92
+
93
+ def profile_data(profile)
94
+ invoke_remote(:profile_data, [@agent_id, profile], :skip_normalization => true) || ''
95
+ end
96
+
97
+ def get_agent_commands
98
+ invoke_remote(:get_agent_commands, [@agent_id])
99
+ end
100
+
101
+ def agent_command_results(results)
102
+ invoke_remote(:agent_command_results, [@agent_id, results])
103
+ end
104
+
105
+ def get_xray_metadata(xray_ids)
106
+ invoke_remote(:get_xray_metadata, [@agent_id, *xray_ids])
107
+ end
108
+
109
+ def analytic_event_data(data)
110
+ invoke_remote(:analytic_event_data, [@agent_id, data], :item_count => data.size)
111
+ end
112
+
113
+ def custom_event_data(data)
114
+ invoke_remote(:custom_event_data, [@agent_id, data], :item_count => data.size)
115
+ end
116
+
117
+ def utilization_data(data)
118
+ invoke_remote(:utilization_data, data)
119
+ end
120
+
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ module OneApm
4
+ module Collector
5
+ module Commands
6
+ class AgentCommand
7
+ attr_reader :id, :name, :arguments
8
+
9
+ def initialize(raw_collector_command)
10
+ @id = raw_collector_command[0]
11
+ @name = raw_collector_command[1]["name"]
12
+ @arguments = raw_collector_command[1]["arguments"]
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,108 @@
1
+ # encoding: utf-8
2
+
3
+ require 'one_apm/agent/threading/agent_thread'
4
+ require 'one_apm/agent/threading/backtrace_service'
5
+ require 'one_apm/agent/threading/thread_profile'
6
+
7
+ module OneApm
8
+ module Collector
9
+ module Commands
10
+
11
+ class ThreadProfilerSession
12
+
13
+ def initialize(backtrace_service)
14
+ @backtrace_service = backtrace_service
15
+ end
16
+
17
+ def handle_start_command(agent_command)
18
+ raise_unsupported_error unless OneApm::Agent::Threading::BacktraceService.is_supported?
19
+ raise_thread_profiler_disabled unless enabled?
20
+ raise_already_started_error if running?
21
+ start(agent_command)
22
+ end
23
+
24
+ def handle_stop_command(agent_command)
25
+ report_data = agent_command.arguments.fetch("report_data", true)
26
+ stop(report_data)
27
+ end
28
+
29
+ def start(agent_command)
30
+ OneApm::Agent.logger.debug("Starting Thread Profiler.")
31
+ profile = @backtrace_service.subscribe(
32
+ OneApm::Agent::Threading::BacktraceService::ALL_TRANSACTIONS,
33
+ agent_command.arguments
34
+ )
35
+
36
+ @started_at = Time.now
37
+ @duration = profile.duration if profile
38
+ end
39
+
40
+ def stop(report_data)
41
+ return unless running?
42
+ OneApm::Agent.logger.debug("Stopping Thread Profiler.")
43
+ @finished_profile = @backtrace_service.harvest(OneApm::Agent::Threading::BacktraceService::ALL_TRANSACTIONS)
44
+ @backtrace_service.unsubscribe(OneApm::Agent::Threading::BacktraceService::ALL_TRANSACTIONS)
45
+ @finished_profile = nil if !report_data
46
+ end
47
+
48
+ def harvest
49
+ OneApm::Agent.logger.debug("Harvesting from Thread Profiler #{@finished_profile.to_log_description unless @finished_profile.nil?}")
50
+ profile = @finished_profile
51
+ @backtrace_service.profile_agent_code = false
52
+ @finished_profile = nil
53
+ @started_at = nil
54
+ profile
55
+ end
56
+
57
+ def enabled?
58
+ OneApm::Agent.config[:'thread_profiler.enabled']
59
+ end
60
+
61
+ def running?
62
+ @backtrace_service.subscribed?(OneApm::Agent::Threading::BacktraceService::ALL_TRANSACTIONS)
63
+ end
64
+
65
+ def ready_to_harvest?
66
+ past_time? || stopped?
67
+ end
68
+
69
+ def past_time?
70
+ @started_at && (Time.now > @started_at + @duration)
71
+ end
72
+
73
+ def stopped?
74
+ !!@finished_profile
75
+ end
76
+
77
+ private
78
+
79
+ def raise_command_error(msg)
80
+ raise OneApm::Collector::AgentCommandRouter::AgentCommandError.new(msg)
81
+ end
82
+
83
+ def raise_unsupported_error
84
+ msg = <<-EOF
85
+ Thread profiling is only supported on 1.9.2 and greater versions of Ruby.
86
+ We detected running agents capable of profiling, but the profile started with
87
+ an agent running Ruby #{RUBY_VERSION}.
88
+
89
+ Profiling again might select an appropriate agent, but we recommend running a
90
+ consistent version of Ruby across your application for better results.
91
+ EOF
92
+ raise_command_error(msg)
93
+ end
94
+
95
+ def raise_thread_profiler_disabled
96
+ msg = "Not starting Thread Profiler because of config 'thread_profiler.enabled' = #{enabled?}"
97
+ raise_command_error(msg)
98
+ end
99
+
100
+ def raise_already_started_error
101
+ msg = "Profile already in progress. Ignoring agent command to start another."
102
+ raise_command_error(msg)
103
+ end
104
+
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require 'forwardable'
4
+
5
+ module OneApm
6
+ module Collector
7
+ module Commands
8
+ class XraySession
9
+ extend Forwardable
10
+
11
+ attr_reader :id, :command_arguments
12
+ attr_reader :xray_session_name, :key_transaction_name,
13
+ :requested_trace_count, :duration, :sample_period
14
+
15
+ def initialize(command_arguments)
16
+ @command_arguments = command_arguments
17
+ @id = command_arguments.fetch("x_ray_id", nil)
18
+ @xray_session_name = command_arguments.fetch("xray_session_name", "")
19
+ @key_transaction_name = command_arguments.fetch("key_transaction_name", "")
20
+ @requested_trace_count = command_arguments.fetch("requested_trace_count", 100)
21
+ @duration = command_arguments.fetch("duration", 86400)
22
+ @sample_period = command_arguments.fetch("sample_period", 0.1)
23
+ @run_profiler = command_arguments.fetch("run_profiler", true)
24
+ end
25
+
26
+ def active?
27
+ @active
28
+ end
29
+
30
+ def run_profiler?
31
+ @run_profiler && OneApm::Agent.config[:'xray_session.allow_profiles']
32
+ end
33
+
34
+ def activate
35
+ @active = true
36
+ @start_time = Time.now
37
+ end
38
+
39
+ def deactivate
40
+ @active = false
41
+ end
42
+
43
+ def requested_period
44
+ @sample_period
45
+ end
46
+
47
+ def finished?
48
+ @start_time + @duration < Time.now
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,156 @@
1
+ # encoding: utf-8
2
+
3
+ require 'forwardable'
4
+ require 'thread'
5
+ require 'one_apm/collector/commands/xray_session'
6
+
7
+ module OneApm
8
+ module Collector
9
+ module Commands
10
+ class XraySessionCollection
11
+ extend Forwardable
12
+
13
+ def initialize(backtrace_service, event_listener)
14
+ @backtrace_service = backtrace_service
15
+
16
+ # This lock protects access to the sessions hash, but it's expected
17
+ # that individual session objects within the hash will be manipulated
18
+ # outside the lock. This is safe because manipulation of the session
19
+ # objects is expected from only a single thread (the harvest thread)
20
+ @sessions_lock = Mutex.new
21
+ @sessions = {}
22
+
23
+ if event_listener
24
+ event_listener.subscribe(:before_harvest, &method(:cleanup_finished_sessions))
25
+ end
26
+ end
27
+
28
+ def handle_active_xray_sessions(agent_command)
29
+ # If X-Rays are disabled, just be quiet about it and don't start the
30
+ # command. Other hosts might be running the X-Ray, so we don't need
31
+ # to bark on every get_agent_commands.
32
+ if !OneApm::Agent.config[:'xray_session.enabled']
33
+ OneApm::Agent.logger.debug("Not responding to X-Ray command because of config 'xray_session.enabled' = #{OneApm::Agent.config[:'xray_session.enabled']}")
34
+ return
35
+ end
36
+
37
+ incoming_ids = agent_command.arguments["xray_ids"]
38
+ deactivate_for_incoming_sessions(incoming_ids)
39
+ activate_sessions(incoming_ids)
40
+ end
41
+
42
+ def session_id_for_transaction_name(name)
43
+ @sessions_lock.synchronize do
44
+ @sessions.keys.find { |id| @sessions[id].key_transaction_name == name }
45
+ end
46
+ end
47
+
48
+ NO_PROFILES = [].freeze
49
+
50
+ def harvest_thread_profiles
51
+ return NO_PROFILES unless OneApm::Agent::Threading::BacktraceService.is_supported?
52
+
53
+ profiles = active_thread_profiling_sessions.map do |session|
54
+ OneApm::Agent.logger.debug("Harvesting profile for X-Ray session #{session.inspect}")
55
+ @backtrace_service.harvest(session.key_transaction_name)
56
+ end
57
+ profiles.reject! {|p| p.empty?}
58
+ profiles.compact
59
+ end
60
+
61
+ def stop_all_sessions
62
+ deactivate_for_incoming_sessions([])
63
+ end
64
+
65
+ def cleanup_finished_sessions
66
+ finished_session_ids.each do |id|
67
+ OneApm::Agent.logger.debug("Finished X-Ray session #{id} by duration. Removing it from active sessions.")
68
+ remove_session_by_id(id)
69
+ end
70
+ end
71
+
72
+
73
+ ### Internals
74
+
75
+ def one_apm_service
76
+ OneApm::Agent.instance.service
77
+ end
78
+
79
+ # These are unsynchonized and should only be used for testing
80
+ def_delegators :@sessions, :[], :include?
81
+
82
+ def active_thread_profiling_sessions
83
+ @sessions_lock.synchronize do
84
+ @sessions.values.select { |s| s.active? && s.run_profiler? }
85
+ end
86
+ end
87
+
88
+ ### Session activation
89
+
90
+ def activate_sessions(incoming_ids)
91
+ lookup_metadata_for(ids_to_activate(incoming_ids)).each do |raw|
92
+ add_session(XraySession.new(raw))
93
+ end
94
+ end
95
+
96
+ def ids_to_activate(incoming_ids)
97
+ @sessions_lock.synchronize { incoming_ids - @sessions.keys }
98
+ end
99
+
100
+ # Please don't hold the @sessions_lock across me! Calling the service
101
+ # is time-consuming, and will block request threads. Which is rude.
102
+ def lookup_metadata_for(ids_to_activate)
103
+ return [] if ids_to_activate.empty?
104
+
105
+ OneApm::Agent.logger.debug("Retrieving metadata for X-Ray sessions #{ids_to_activate.inspect}")
106
+ one_apm_service.get_xray_metadata(ids_to_activate)
107
+ end
108
+
109
+ def add_session(session)
110
+ OneApm::Agent.logger.debug("Adding X-Ray session #{session.inspect}")
111
+ OneApm::Agent.increment_metric("Supportability/XraySessions/Starts")
112
+
113
+ @sessions_lock.synchronize { @sessions[session.id] = session }
114
+
115
+ session.activate
116
+ if session.run_profiler?
117
+ @backtrace_service.subscribe(session.key_transaction_name, session.command_arguments)
118
+ end
119
+ end
120
+
121
+ ### Session deactivation
122
+
123
+ def deactivate_for_incoming_sessions(incoming_ids)
124
+ ids_to_remove(incoming_ids).each do |session_id|
125
+ remove_session_by_id(session_id)
126
+ end
127
+ end
128
+
129
+ def ids_to_remove(incoming_ids)
130
+ @sessions_lock.synchronize { @sessions.keys - incoming_ids }
131
+ end
132
+
133
+ def remove_session_by_id(id)
134
+ session = @sessions_lock.synchronize { @sessions.delete(id) }
135
+
136
+ if session
137
+ OneApm::Agent.logger.debug("Removing X-Ray session #{session.inspect}")
138
+ OneApm::Agent.increment_metric("Supportability/XraySessions/Stops")
139
+
140
+ if session.run_profiler?
141
+ @backtrace_service.unsubscribe(session.key_transaction_name)
142
+ end
143
+ session.deactivate
144
+ end
145
+ end
146
+
147
+ def finished_session_ids
148
+ @sessions_lock.synchronize do
149
+ @sessions.map{|k, s| k if s.finished?}.compact
150
+ end
151
+ end
152
+
153
+ end
154
+ end
155
+ end
156
+ end