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,37 @@
1
+ # encoding: utf-8
2
+
3
+ module OneApm
4
+ module Agent
5
+ module Datastores
6
+ module Mongo
7
+ module Obfuscator
8
+
9
+ WHITELIST = [:operation].freeze
10
+
11
+ def self.obfuscate_statement(source, whitelist=WHITELIST)
12
+ obfuscated = {}
13
+ source.each do |key, value|
14
+ if whitelist.include?(key)
15
+ obfuscated[key] = value
16
+ else
17
+ obfuscated[key] = obfuscate_value(value, whitelist)
18
+ end
19
+ end
20
+
21
+ obfuscated
22
+ end
23
+
24
+ def self.obfuscate_value(value, whitelist)
25
+ if value.is_a?(Hash)
26
+ obfuscate_statement(value, whitelist)
27
+ elsif value.is_a?(Array)
28
+ value.map {|v| obfuscate_value(v, whitelist)}
29
+ else
30
+ '?'
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ require 'one_apm/agent/datastores/mongo/obfuscator'
4
+
5
+ module OneApm
6
+ module Agent
7
+ module Datastores
8
+ module Mongo
9
+ module StatementFormatter
10
+
11
+ PLAINTEXT_KEYS = [
12
+ :database,
13
+ :collection,
14
+ :operation,
15
+ :fields,
16
+ :skip,
17
+ :limit,
18
+ :order
19
+ ]
20
+
21
+ OBFUSCATE_KEYS = [
22
+ :selector
23
+ ]
24
+
25
+ def self.format(statement, operation)
26
+ return nil unless OneApm::Agent.config[:'mongo.capture_queries']
27
+
28
+ result = { :operation => operation }
29
+
30
+ PLAINTEXT_KEYS.each do |key|
31
+ result[key] = statement[key] if statement.key?(key)
32
+ end
33
+
34
+ OBFUSCATE_KEYS.each do |key|
35
+ if statement.key?(key) && statement[key]
36
+ obfuscated = obfuscate(statement[key])
37
+ result[key] = obfuscated if obfuscated
38
+ end
39
+ end
40
+ result
41
+ end
42
+
43
+ def self.obfuscate(statement)
44
+ statement = Obfuscator.obfuscate_statement(statement) if OneApm::Agent.config[:'mongo.obfuscate_queries']
45
+ statement
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+
3
+ module OneApm::Agent
4
+ class EventListener
5
+
6
+ attr_accessor :runaway_threshold
7
+
8
+ def initialize
9
+ @events = {}
10
+ @runaway_threshold = 100
11
+ end
12
+
13
+ def subscribe(event, &handler)
14
+ @events[event] ||= []
15
+ @events[event] << handler
16
+ check_for_runaway_subscriptions(event)
17
+ end
18
+
19
+ def check_for_runaway_subscriptions(event)
20
+ count = @events[event].size
21
+ OneApm::Agent.logger.debug("Run-away event subscription on #{event}? Subscribed #{count}") if count > @runaway_threshold
22
+ end
23
+
24
+ def clear
25
+ @events.clear
26
+ end
27
+
28
+ def notify(event, *args)
29
+ return unless @events.has_key?(event)
30
+
31
+ @events[event].each do |handler|
32
+ begin
33
+ handler.call(*args)
34
+ rescue => err
35
+ OneApm::Agent.logger.debug("Failure during notify for #{event}", err)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,191 @@
1
+ # encoding: utf-8
2
+
3
+ require 'thread'
4
+
5
+ module OneApm
6
+ module Agent
7
+ class EventLoop
8
+ class Timer
9
+
10
+ attr_reader :next_fire_time, :event, :interval, :last_fired_at
11
+
12
+ def initialize(interval, event, repeat=false)
13
+ @interval = interval
14
+ @event = event
15
+ @repeat = repeat
16
+ @started_at = Time.now
17
+ @last_fired_at = nil
18
+ reschedule
19
+ end
20
+
21
+ def reschedule
22
+ @next_fire_time = calculate_next_fire_time
23
+ end
24
+
25
+ def advance(amount)
26
+ @next_fire_time -= amount
27
+ end
28
+
29
+ def last_interval_start
30
+ @last_fired_at || @started_at
31
+ end
32
+
33
+ def calculate_next_fire_time
34
+ now = Time.now
35
+ return now if @interval == 0
36
+ fire_time = @last_fired_at || now
37
+ while fire_time <= now
38
+ fire_time += @interval
39
+ end
40
+ fire_time
41
+ end
42
+
43
+ def set_fired_time
44
+ @last_fired_at = Time.now
45
+ end
46
+
47
+ def due?(now=Time.now)
48
+ now >= @next_fire_time
49
+ end
50
+
51
+ def finished?
52
+ !@repeat && @last_fired_at
53
+ end
54
+
55
+ end
56
+
57
+ def initialize
58
+ @self_pipe_rd, @self_pipe_wr = IO.pipe
59
+ @event_queue = Queue.new
60
+ @stopped = false
61
+ @timers = {}
62
+
63
+ @subscriptions = Hash.new { |h,k| h[k] = [] }
64
+ @subscriptions[:__add_timer] << Proc.new { |t| set_timer(t) }
65
+ @subscriptions[:__add_event] << Proc.new { |e, blk| @subscriptions[e] << blk }
66
+ end
67
+
68
+ def set_timer(timer)
69
+ existing_timer = @timers[timer.event]
70
+
71
+ if existing_timer
72
+ elapsed_interval = Time.now - existing_timer.last_interval_start
73
+ timer.advance(elapsed_interval)
74
+ end
75
+
76
+ @timers[timer.event] = timer
77
+
78
+ fire_timer(timer)
79
+ end
80
+
81
+ def next_timeout
82
+ return nil if @timers.empty?
83
+ timeout = @timers.values.map(&:next_fire_time).min - Time.now
84
+ timeout < 0 ? 0 : timeout
85
+ end
86
+
87
+ def stopped?
88
+ @stopped
89
+ end
90
+
91
+ def stop
92
+ @stopped = true
93
+ wakeup
94
+ end
95
+
96
+ def run
97
+ OneApm::Agent.logger.debug "Running event loop"
98
+ while !stopped?
99
+ run_once
100
+ end
101
+ end
102
+
103
+ def run_once(nonblock=false)
104
+ wait_to_run(nonblock)
105
+
106
+ prune_timers
107
+ fire_timers
108
+
109
+ until @event_queue.empty?
110
+ evt, args = @event_queue.pop
111
+ dispatch_event(evt, args)
112
+ reschedule_timer_for_event(evt)
113
+ end
114
+ end
115
+
116
+ def wait_to_run(nonblock)
117
+ timeout = nonblock ? 0 : next_timeout
118
+ ready = IO.select([@self_pipe_rd], nil, nil, timeout)
119
+
120
+ if ready && ready[0] && ready[0][0] && ready[0][0] == @self_pipe_rd
121
+ @self_pipe_rd.read(1)
122
+ end
123
+ end
124
+
125
+ def fire_timers
126
+ @timers.each do |event, timer|
127
+ fire_timer(timer)
128
+ end
129
+ end
130
+
131
+ def fire_timer(timer)
132
+ if timer.due?
133
+ @event_queue << [timer.event]
134
+ timer.set_fired_time
135
+ end
136
+ end
137
+
138
+ def prune_timers
139
+ @timers.delete_if { |e, t| t.finished? }
140
+ end
141
+
142
+ def dispatch_event(event, args)
143
+ OneApm::Agent.logger.debug("EventLoop: Dispatching event '#{event}' with #{@subscriptions[event].size} callback(s).")
144
+
145
+ errors = []
146
+ @subscriptions[event].each do |s|
147
+ begin
148
+ s.call(*args)
149
+ rescue OneApm::ForceRestartException, OneApm::ForceDisconnectException
150
+ raise
151
+ rescue => e
152
+ errors << e
153
+ end
154
+ end
155
+
156
+ if !errors.empty?
157
+ OneApm::Agent.logger.error "#{errors.size} error(s) running task for event '#{event}' in Agent Event Loop:", *errors
158
+ end
159
+ end
160
+
161
+ def reschedule_timer_for_event(e)
162
+ @timers[e].reschedule if @timers[e]
163
+ end
164
+
165
+ def on(event, &blk)
166
+ fire(:__add_event, event, blk)
167
+ end
168
+
169
+ def fire(event, *args)
170
+ @event_queue << [event, args]
171
+ wakeup
172
+ end
173
+
174
+ def fire_every(interval, event)
175
+ OneApm::Agent.logger.debug "Firing event #{event} every #{interval} seconds."
176
+ fire(:__add_timer, Timer.new(interval, event, true))
177
+ end
178
+
179
+ def fire_after(interval, event)
180
+ OneApm::Agent.logger.debug "Firing event #{event} after #{interval} seconds."
181
+ fire(:__add_timer, Timer.new(interval, event, false))
182
+ end
183
+
184
+ def wakeup
185
+ @self_pipe_wr.write_nonblock '.'
186
+ rescue Errno::EAGAIN
187
+ OneApm::Agent.logger.debug "Failed to wakeup event loop"
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,97 @@
1
+ # encoding: utf-8
2
+
3
+ require 'thread'
4
+ module OneApm
5
+ module Agent
6
+
7
+ # A worker loop executes a set of registered tasks on a single thread.
8
+ # A task is a proc or block with a specified call period in seconds.
9
+ class WorkerLoop
10
+
11
+ attr_accessor :period, :propagate_errors
12
+ attr_reader :iterations
13
+
14
+ # Optional argument :duration (in seconds) for how long the worker loop runs
15
+ # or :limit (integer) for max number of iterations
16
+ def initialize(opts={})
17
+ @should_run = true
18
+ @next_invocation_time = Time.now
19
+ @period = 60.0
20
+ @duration = opts[:duration] if opts[:duration]
21
+ @limit = opts[:limit] if opts[:limit]
22
+ @iterations = 0
23
+ @propagate_errors = opts.fetch(:propagate_errors, false)
24
+ end
25
+
26
+ # Reset state that is changed by running the worker loop
27
+ def setup(period, task)
28
+ @task = task
29
+ @period = period if period
30
+ @should_run = true
31
+ @iterations = 0
32
+
33
+ now = Time.now
34
+ @deadline = now + @duration if @duration
35
+ @next_invocation_time = (now + @period)
36
+ end
37
+
38
+ # Run infinitely, calling the registered tasks at their specified
39
+ # call periods. The caller is responsible for creating the thread
40
+ # that runs this worker loop. This will run the task immediately.
41
+ def run(period=nil, &block)
42
+ setup(period, block)
43
+ while keep_running? do
44
+ sleep_time = schedule_next_invocation
45
+ sleep(sleep_time) if sleep_time > 0
46
+ run_task if keep_running?
47
+ @iterations += 1
48
+ end
49
+ end
50
+
51
+ def schedule_next_invocation
52
+ now = Time.now
53
+ while @next_invocation_time <= now && @period > 0
54
+ @next_invocation_time += @period
55
+ end
56
+ @next_invocation_time - Time.now
57
+ end
58
+
59
+ # a simple accessor for @should_run
60
+ def keep_running?
61
+ @should_run && under_duration? && under_limit?
62
+ end
63
+
64
+ def under_duration?
65
+ !@deadline || Time.now < @deadline
66
+ end
67
+
68
+ def under_limit?
69
+ @limit.nil? || @iterations < @limit
70
+ end
71
+
72
+ # Sets @should_run to false. Returns false
73
+ def stop
74
+ @should_run = false
75
+ end
76
+
77
+ # Executes the block given to the worker loop, and handles many
78
+ # possible errors. Also updates the execution time so that the
79
+ # next run occurs on schedule, even if we execute at some odd time
80
+ def run_task
81
+ if @propagate_errors
82
+ @task.call
83
+ else
84
+ begin
85
+ @task.call
86
+ rescue OneApm::ForceRestartException, OneApm::ForceDisconnectException
87
+ # blow out the loop
88
+ raise
89
+ rescue => e
90
+ # Don't blow out the stack for anything that hasn't already propagated
91
+ ::OneApm::Agent.logger.error "Error running task in Agent Worker Loop:", e
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,48 @@
1
+ # encoding: utf-8
2
+
3
+ module OneApm
4
+ module Agent
5
+ class Harvester
6
+
7
+ attr_accessor :starting_pid
8
+
9
+ # Inject target for after_fork call to avoid spawning thread in tests
10
+ def initialize(events, after_forker = OneApm::Agent)
11
+ # We intentionally don't set our pid as started at this point.
12
+ # Startup routines must call mark_started when they consider us set!
13
+ @starting_pid = nil
14
+ @after_forker = after_forker
15
+
16
+ if events
17
+ events.subscribe(:start_transaction, &method(:on_transaction))
18
+ end
19
+ end
20
+
21
+ def on_transaction(*_)
22
+ return unless restart_in_children_enabled? && needs_restart? && harvest_thread_enabled?
23
+
24
+ restart_harvest_thread
25
+ end
26
+
27
+ def mark_started(pid = Process.pid)
28
+ @starting_pid = pid
29
+ end
30
+
31
+ def needs_restart?(pid = Process.pid)
32
+ @starting_pid != pid
33
+ end
34
+
35
+ def restart_in_children_enabled?
36
+ OneApm::Agent.config[:restart_thread_in_children]
37
+ end
38
+
39
+ def harvest_thread_enabled?
40
+ !OneApm::Agent.config[:disable_harvest_thread]
41
+ end
42
+
43
+ def restart_harvest_thread
44
+ @after_forker.after_fork(:force_reconnect => true)
45
+ end
46
+ end
47
+ end
48
+ end