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,175 @@
1
+ module OneApm
2
+ module Agent
3
+ class Agent
4
+ # This module is an artifact of a refactoring of the connect
5
+ # method - all of its methods are used in that context, so it
6
+ # can be refactored at will. It should be fully tested
7
+ module Connect
8
+ # number of attempts we've made to contact the server
9
+ attr_accessor :connect_attempts
10
+
11
+ # Disconnect just sets connected to false, which prevents
12
+ # the agent from trying to connect again
13
+ def disconnect
14
+ @connect_state = :disconnected
15
+ true
16
+ end
17
+
18
+ def connected?
19
+ @connect_state == :connected
20
+ end
21
+
22
+ def disconnected?
23
+ @connect_state == :disconnected
24
+ end
25
+
26
+ # Don't connect if we're already connected, or if we tried to connect
27
+ # and were rejected with prejudice because of a license issue, unless
28
+ # we're forced to by force_reconnect.
29
+ def should_connect?(force = false)
30
+ force || (!connected? && !disconnected?)
31
+ end
32
+
33
+ # Retry period is a minute for each failed attempt that
34
+ # we've made. This should probably do some sort of sane TCP
35
+ # backoff to prevent hammering the server, but a minute for
36
+ # each attempt seems to work reasonably well.
37
+ def connect_retry_period
38
+ [600, connect_attempts * 60].min
39
+ end
40
+
41
+ def note_connect_failure
42
+ self.connect_attempts += 1
43
+ end
44
+
45
+ # When we have a problem connecting to the server, we need
46
+ # to tell the user what happened, since this is not an error
47
+ # we can handle gracefully.
48
+ def log_error(error)
49
+ ::OneApm::Agent.logger.error "Error establishing connection with OneApm Service at #{@service.server}:", error
50
+ end
51
+
52
+ # When the server sends us an error with the license key, we
53
+ # want to tell the user that something went wrong, and let
54
+ # them know where to go to get a valid license key
55
+ #
56
+ # After this runs, it disconnects the agent so that it will
57
+ # no longer try to connect to the server, saving the
58
+ # application and the server load
59
+ def handle_license_error(error)
60
+ ::OneApm::Agent.logger.error( \
61
+ error.message, \
62
+ "Visit oneapm.com to obtain a valid license key, or to upgrade your account.")
63
+ disconnect
64
+ end
65
+
66
+ def handle_unrecoverable_agent_error(error)
67
+ ::OneApm::Agent.logger.error(error.message)
68
+ disconnect
69
+ shutdown
70
+ end
71
+
72
+ def generate_environment_report
73
+ @environment_report = environment_for_connect
74
+ end
75
+
76
+ # Checks whether we should send environment info, and if so,
77
+ # returns the snapshot from the local environment.
78
+ # Generating the EnvironmentReport has the potential to trigger
79
+ # require calls in Rails environments, so this method should only
80
+ # be called synchronously from on the main thread.
81
+ def environment_for_connect
82
+ Agent.config[:send_environment_info] ? Array(EnvironmentReport.new) : []
83
+ end
84
+
85
+ # We've seen objects in the environment report (Rails.env in
86
+ # particular) that can't seralize to JSON. Cope with that here and
87
+ # clear out so downstream code doesn't have to check again.
88
+ def sanitize_environment_report
89
+ if !@service.valid_to_marshal?(@environment_report)
90
+ @environment_report = []
91
+ end
92
+ end
93
+
94
+ # Initializes the hash of settings that we send to the
95
+ # server. Returns a literal hash containing the options
96
+ def connect_settings
97
+ sanitize_environment_report
98
+ {
99
+ :pid => $$,
100
+ :host => local_host,
101
+ :app_name => Agent.config.app_names,
102
+ :language => 'ruby',
103
+ :labels => Agent.config.parsed_labels,
104
+ :agent_version => OneApm::VERSION::STRING,
105
+ :environment => @environment_report,
106
+ :settings => Agent.config.to_collector_hash,
107
+ :high_security => Agent.config[:high_security],
108
+ :identifier => "ruby:#{local_host}"
109
+ }
110
+ end
111
+
112
+ # apdex_f is always 4 times the apdex_t
113
+ def apdex_f
114
+ (4 * Agent.config[:apdex_t]).to_f
115
+ end
116
+
117
+ # Sets the collector host and connects to the server, then
118
+ # invokes the final configuration with the returned data
119
+ def query_server_for_configuration
120
+ finish_setup(connect_to_server)
121
+ end
122
+
123
+ # Returns connect data passed back from the server
124
+ def connect_to_server
125
+ @service.connect(connect_settings)
126
+ end
127
+
128
+ # Takes a hash of configuration data returned from the
129
+ # server and uses it to set local variables and to
130
+ # initialize various parts of the agent that are configured
131
+ # separately.
132
+ #
133
+ # Can accommodate most arbitrary data - anything extra is
134
+ # ignored unless we say to do something with it here.
135
+ def finish_setup(config_data)
136
+ return if config_data == nil
137
+
138
+ @service.agent_id = config_data['agent_run_id'] if @service
139
+
140
+ ::OneApm::Agent.logger.debug "Server provided config: #{config_data.inspect}"
141
+ server_config = OneApm::Configuration::ServerSource.new(config_data, Agent.config)
142
+ Agent.config.replace_or_add_config(server_config)
143
+ log_connection!(config_data) if @service
144
+
145
+ @transaction_rules = OneApm::Support::RulesEngine.create_transaction_rules(config_data)
146
+ @stats_engine.metric_rules = OneApm::Support::RulesEngine.create_metric_rules(config_data)
147
+
148
+ # If you're adding something else here to respond to the server-side config,
149
+ # use Agent.instance.events.subscribe(:finished_configuring) callback instead!
150
+ end
151
+
152
+ def local_host
153
+ @local_host ||= OneApm::Agent::Hostname.get
154
+ end
155
+
156
+ # Logs when we connect to the server, for debugging purposes
157
+ # - makes sure we know if an agent has not connected
158
+ def log_connection!(config_data)
159
+ ::OneApm::Agent.logger.debug "Connected to OneApm Service at #{@service.collector.name}"
160
+ ::OneApm::Agent.logger.debug "Agent Run = #{@service.agent_id}."
161
+ ::OneApm::Agent.logger.debug "Connection data = #{config_data.inspect}"
162
+ if config_data['messages'] && config_data['messages'].any?
163
+ log_collector_messages(config_data['messages'])
164
+ end
165
+ end
166
+
167
+ def log_collector_messages(messages)
168
+ messages.each do |message|
169
+ ::OneApm::Agent.logger.send(message['level'].downcase, message['message'])
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,218 @@
1
+ module OneApm
2
+ module Agent
3
+ class Agent
4
+ module ContainerDataManager
5
+
6
+ # the statistics engine that holds all the timeslice data
7
+ attr_reader :stats_engine
8
+ # the transaction sampler that handles recording transactions
9
+ attr_reader :transaction_sampler
10
+ attr_reader :sql_sampler
11
+ # manages agent commands we receive from the collector, and the handlers
12
+ attr_reader :agent_command_router
13
+ # error collector is a simple collection of recorded errors
14
+ attr_reader :error_collector
15
+ attr_reader :custom_event_aggregator
16
+
17
+ def merge_data_for_endpoint(endpoint, data)
18
+ if data && !data.empty?
19
+ container_for_endpoint(endpoint).merge!(data)
20
+ end
21
+ rescue => e
22
+ OneApm::Agent.logger.error("Error while merging #{endpoint} data from child: ", e)
23
+ end
24
+
25
+ # Clear out the metric data, errors, and transaction traces, etc.
26
+ def drop_buffered_data
27
+ @stats_engine.reset!
28
+ @error_collector.reset!
29
+ @transaction_sampler.reset!
30
+ @transaction_event_aggregator.reset!
31
+ @custom_event_aggregator.reset!
32
+ @sql_sampler.reset!
33
+ end
34
+
35
+ private
36
+
37
+ def init_containers(events)
38
+ @stats_engine = OneApm::Collector::StatsEngine.new
39
+ @transaction_sampler = OneApm::Collector::TransactionSampler.new
40
+ @sql_sampler = OneApm::Collector::SqlSampler.new
41
+ @error_collector = OneApm::Collector::ErrorCollector.new
42
+ @custom_event_aggregator = OneApm::Collector::CustomEventAggregator.new
43
+ @transaction_event_aggregator = OneApm::Collector::TransactionEventAggregator.new(@events)
44
+ @utilization_data = OneApm::Collector::UtilizationData.new
45
+ @agent_command_router = OneApm::Collector::AgentCommandRouter.new(@events)
46
+ end
47
+
48
+ def container_for_endpoint(endpoint)
49
+ case endpoint
50
+ when :metric_data then @stats_engine
51
+ when :transaction_sample_data then @transaction_sampler
52
+ when :sql_trace_data then @sql_sampler
53
+ when :error_data then @error_collector
54
+ when :custom_event_data then @custom_event_aggregator
55
+ when :analytic_event_data then @transaction_event_aggregator
56
+ end
57
+ end
58
+
59
+ # Harvests data from the given container, sends it to the named endpoint
60
+ # on the service, and automatically merges back in upon a recoverable
61
+ # failure.
62
+ #
63
+ # The given container should respond to:
64
+ #
65
+ # #harvest!
66
+ # returns an enumerable collection of data items to be sent to the
67
+ # collector.
68
+ #
69
+ # #reset!
70
+ # drop any stored data and reset to a clean state.
71
+ #
72
+ # #merge!(items)
73
+ # merge the given items back into the internal buffer of the
74
+ # container, so that they may be harvested again later.
75
+ #
76
+ def harvest_and_send_from_container(container, endpoint)
77
+ items = harvest_from_container(container, endpoint)
78
+ send_data_to_endpoint(endpoint, items, container) unless items.empty?
79
+ end
80
+
81
+ def harvest_from_container(container, endpoint)
82
+ items = []
83
+ begin
84
+ items = container.harvest!
85
+ rescue => e
86
+ OneApm::Agent.logger.error("Failed to harvest #{endpoint} data, resetting. Error: ", e)
87
+ container.reset!
88
+ end
89
+ items
90
+ end
91
+
92
+ def send_data_to_endpoint(endpoint, items, container)
93
+ OneApm::Agent.logger.debug("Sending #{items.size} items to #{endpoint}")
94
+ begin
95
+ @service.send(endpoint, items)
96
+ rescue ForceRestartException, ForceDisconnectException
97
+ raise
98
+ rescue SerializationError => e
99
+ OneApm::Agent.logger.warn("Failed to serialize data for #{endpoint}, discarding. Error: ", e)
100
+ rescue UnrecoverableServerException => e
101
+ OneApm::Agent.logger.warn("#{endpoint} data was rejected by remote service, discarding. Error: ", e)
102
+ rescue ServerConnectionException => e
103
+ log_remote_unavailable(endpoint, e)
104
+ container.merge!(items)
105
+ rescue => e
106
+ OneApm::Agent.logger.info("Unable to send #{endpoint} data, will try again later. Error: ", e)
107
+ container.merge!(items)
108
+ end
109
+ end
110
+
111
+ def harvest_and_send_timeslice_data
112
+ OneApm::Agent::BusyCalculator.harvest_busy
113
+ harvest_and_send_from_container(@stats_engine, :metric_data)
114
+ end
115
+
116
+ def harvest_and_send_slowest_sql
117
+ harvest_and_send_from_container(@sql_sampler, :sql_trace_data)
118
+ end
119
+
120
+ # This handles getting the transaction traces and then sending
121
+ # them across the wire. This includes gathering SQL
122
+ # explanations, stripping out stack traces, and normalizing
123
+ # SQL. note that we explain only the sql statements whose
124
+ # segments' execution times exceed our threshold.
125
+ def harvest_and_send_transaction_traces
126
+ harvest_and_send_from_container(@transaction_sampler, :transaction_sample_data)
127
+ end
128
+
129
+ def harvest_and_send_for_agent_commands
130
+ harvest_and_send_from_container(@agent_command_router, :profile_data)
131
+ end
132
+
133
+ def harvest_and_send_errors
134
+ harvest_and_send_from_container(@error_collector, :error_data)
135
+ end
136
+
137
+ def harvest_and_send_analytic_event_data
138
+ harvest_and_send_from_container(@transaction_event_aggregator, :analytic_event_data)
139
+ harvest_and_send_from_container(@custom_event_aggregator, :custom_event_data)
140
+ end
141
+
142
+ def harvest_and_send_utilization_data
143
+ harvest_and_send_from_container(@utilization_data, :utilization_data)
144
+ end
145
+
146
+ def transmit_data
147
+ harvest_lock.synchronize do
148
+ transmit_data_already_locked
149
+ end
150
+ end
151
+
152
+ def transmit_event_data
153
+ transmit_single_data_type(:harvest_and_send_analytic_event_data, "TransactionEvent")
154
+ end
155
+
156
+ def transmit_utilization_data
157
+ transmit_single_data_type(:harvest_and_send_utilization_data, "UtilizationData")
158
+ end
159
+
160
+ def transmit_single_data_type(harvest_method, supportability_name)
161
+ now = Time.now
162
+
163
+ msg = "Sending #{harvest_method.to_s.gsub("harvest_and_send_", "")} to OneApm Service"
164
+ ::OneApm::Agent.logger.debug msg
165
+
166
+ harvest_lock.synchronize do
167
+ @service.session do # use http keep-alive
168
+ self.send(harvest_method)
169
+ end
170
+ end
171
+ ensure
172
+ duration = (Time.now - now).to_f
173
+ OneApm::Agent.record_metric("Supportability/#{supportability_name}Harvest", duration)
174
+ end
175
+
176
+ # This method is expected to only be called with the harvest_lock already held
177
+ def transmit_data_already_locked
178
+ now = Time.now
179
+ ::OneApm::Agent.logger.debug "Sending data to OneApm Service"
180
+
181
+ @events.notify(:before_harvest)
182
+ @service.session do
183
+ harvest_and_send_errors
184
+ harvest_and_send_transaction_traces
185
+ harvest_and_send_slowest_sql
186
+ harvest_and_send_timeslice_data
187
+
188
+ check_for_and_handle_agent_commands
189
+ harvest_and_send_for_agent_commands
190
+ end
191
+ ensure
192
+ OneApm::Agent::Database.close_connections
193
+ duration = (Time.now - now).to_f
194
+ OneApm::Agent.record_metric('Supportability/Harvest', duration)
195
+ end
196
+
197
+ def check_for_and_handle_agent_commands
198
+ begin
199
+ @agent_command_router.check_for_and_handle_agent_commands
200
+ rescue ForceRestartException, ForceDisconnectException
201
+ raise
202
+ rescue ServerConnectionException => e
203
+ log_remote_unavailable(:get_agent_commands, e)
204
+ rescue => e
205
+ OneApm::Agent.logger.info("Error during check_for_and_handle_agent_commands, will retry later: ", e)
206
+ end
207
+ end
208
+
209
+ def log_remote_unavailable(endpoint, e)
210
+ OneApm::Agent.logger.debug("Unable to send #{endpoint} data, will try again later. Error: ", e)
211
+ OneApm::Agent.record_metric("Supportability/remote_unavailable", 0.0)
212
+ OneApm::Agent.record_metric("Supportability/remote_unavailable/#{endpoint.to_s}", 0.0)
213
+ end
214
+
215
+ end
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,96 @@
1
+ module OneApm
2
+ module Agent
3
+ class Agent
4
+ module ForkableDispatcherFunctions
5
+
6
+ # This method should be called in a forked process after a fork.
7
+ # It assumes the parent process initialized the agent, but does
8
+ # not assume the agent started.
9
+ #
10
+ # The call is idempotent, but not re-entrant.
11
+ #
12
+ # * It clears any metrics carried over from the parent process
13
+ # * Restarts the sampler thread if necessary
14
+ # * Initiates a new agent run and worker loop unless that was done
15
+ # in the parent process and +:force_reconnect+ is not true
16
+ #
17
+ # Options:
18
+ # * <tt>:force_reconnect => true</tt> to force the spawned process to
19
+ # establish a new connection, such as when forking a long running process.
20
+ # The default is false--it will only connect to the server if the parent
21
+ # had not connected.
22
+ # * <tt>:keep_retrying => false</tt> if we try to initiate a new
23
+ # connection, this tells me to only try it once so this method returns
24
+ # quickly if there is some kind of latency with the server.
25
+ def after_fork(options={})
26
+ needs_restart = false
27
+ @after_fork_lock.synchronize do
28
+ needs_restart = @harvester.needs_restart?
29
+ @harvester.mark_started
30
+ end
31
+
32
+ return if !needs_restart ||
33
+ !Agent.config[:agent_enabled] ||
34
+ !Agent.config[:monitor_mode] ||
35
+ disconnected?
36
+
37
+ ::OneApm::Agent.logger.debug "Starting the worker thread in #{Process.pid} (parent #{Process.ppid}) after forking."
38
+
39
+ channel_id = options[:report_to_channel]
40
+ install_pipe_service(channel_id) if channel_id
41
+
42
+ # Clear out locks and stats left over from parent process
43
+ reset_objects_with_locks
44
+ drop_buffered_data
45
+
46
+ setup_and_start_agent(options)
47
+ end
48
+
49
+ def install_pipe_service(channel_id)
50
+ @service = OneApm::Agent::PipeService.new(channel_id)
51
+ if connected?
52
+ @connected_pid = Process.pid
53
+ else
54
+ ::OneApm::Agent.logger.debug("Child process #{Process.pid} not reporting to non-connected parent (process #{Process.ppid}).")
55
+ @service.shutdown(Time.now)
56
+ disconnect
57
+ end
58
+ end
59
+
60
+ # Synchronize with the harvest loop. If the harvest thread has taken
61
+ # a lock (DNS lookups, backticks, agent-owned locks, etc), and we
62
+ # fork while locked, this can deadlock child processes. For more
63
+ # details, see https://github.com/resque/resque/issues/1101
64
+ def synchronize_with_harvest
65
+ harvest_lock.synchronize do
66
+ yield
67
+ end
68
+ end
69
+
70
+ # Clear out state for any objects that we know lock from our parents
71
+ # This is necessary for cases where we're in a forked child and Ruby
72
+ # might be holding locks for background thread that aren't there anymore.
73
+ def reset_objects_with_locks
74
+ @stats_engine = OneApm::Collector::StatsEngine.new
75
+ reset_harvest_locks
76
+ end
77
+
78
+ # Some forking cases (like Resque) end up with harvest lock from the
79
+ # parent process orphaned in the child. Let it go before we proceed.
80
+ def reset_harvest_locks
81
+ return if harvest_lock.nil?
82
+
83
+ harvest_lock.unlock if harvest_lock.locked?
84
+ end
85
+
86
+ def flush_pipe_data
87
+ if connected? && @service.is_a?(::OneApm::Agent::PipeService)
88
+ transmit_data
89
+ transmit_event_data
90
+ end
91
+ end
92
+
93
+ end
94
+ end
95
+ end
96
+ end