instana 1.11.6 → 1.209.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (274) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +263 -0
  3. data/.editorconfig +10 -0
  4. data/.github/ISSUE_TEMPLATE/bug.yml +39 -0
  5. data/.github/ISSUE_TEMPLATE/config.yml +5 -0
  6. data/.gitignore +3 -0
  7. data/.rubocop.yml +14 -1136
  8. data/.rubocop_todo.yml +1140 -0
  9. data/Appraisals +124 -0
  10. data/Gemfile +14 -32
  11. data/LICENSE +2 -1
  12. data/README.md +2 -6
  13. data/Rakefile +18 -49
  14. data/bin/console +8 -4
  15. data/docker-compose.yml +20 -0
  16. data/examples/opentracing.rb +4 -0
  17. data/examples/tracing.rb +4 -0
  18. data/extras/license_header.rb +44 -0
  19. data/gemfiles/.bundle/config +1 -2
  20. data/gemfiles/aws_30.gemfile +22 -0
  21. data/gemfiles/cuba_30.gemfile +18 -0
  22. data/gemfiles/dalli_20.gemfile +18 -0
  23. data/gemfiles/excon_02.gemfile +18 -0
  24. data/gemfiles/excon_021.gemfile +18 -0
  25. data/gemfiles/excon_079.gemfile +18 -0
  26. data/gemfiles/graphql_10.gemfile +18 -0
  27. data/gemfiles/grpc_10.gemfile +18 -0
  28. data/gemfiles/mongo_216.gemfile +18 -0
  29. data/gemfiles/net_http_01.gemfile +17 -0
  30. data/gemfiles/rack_16.gemfile +18 -0
  31. data/gemfiles/rack_20.gemfile +18 -0
  32. data/gemfiles/rails_42.gemfile +21 -0
  33. data/gemfiles/rails_50.gemfile +21 -0
  34. data/gemfiles/rails_52.gemfile +21 -0
  35. data/gemfiles/rails_60.gemfile +21 -0
  36. data/gemfiles/redis_40.gemfile +18 -0
  37. data/gemfiles/resque_122.gemfile +19 -0
  38. data/gemfiles/resque_20.gemfile +18 -0
  39. data/gemfiles/rest_client_16.gemfile +18 -0
  40. data/gemfiles/rest_client_20.gemfile +18 -0
  41. data/gemfiles/roda_20.gemfile +18 -0
  42. data/gemfiles/roda_30.gemfile +18 -0
  43. data/gemfiles/shoryuken_50.gemfile +19 -0
  44. data/gemfiles/sidekiq_42.gemfile +18 -0
  45. data/gemfiles/sidekiq_50.gemfile +18 -0
  46. data/gemfiles/sinatra_14.gemfile +18 -0
  47. data/instana.gemspec +8 -14
  48. data/lib/instana/activator.rb +58 -0
  49. data/lib/instana/activators/action_cable.rb +24 -0
  50. data/lib/instana/activators/action_controller_api.rb +21 -0
  51. data/lib/instana/activators/action_controller_base.rb +21 -0
  52. data/lib/instana/activators/action_mailer.rb +22 -0
  53. data/lib/instana/activators/action_view.rb +21 -0
  54. data/lib/instana/activators/active_job.rb +21 -0
  55. data/lib/instana/activators/active_record.rb +21 -0
  56. data/lib/instana/activators/aws_sdk_dynamodb.rb +20 -0
  57. data/lib/instana/activators/aws_sdk_lambda.rb +20 -0
  58. data/lib/instana/activators/aws_sdk_s3.rb +20 -0
  59. data/lib/instana/activators/aws_sdk_sns.rb +20 -0
  60. data/lib/instana/activators/aws_sdk_sqs.rb +20 -0
  61. data/lib/instana/activators/cuba.rb +21 -0
  62. data/lib/instana/activators/dalli.rb +23 -0
  63. data/lib/instana/activators/excon.rb +20 -0
  64. data/lib/instana/activators/graphql.rb +22 -0
  65. data/lib/instana/activators/grpc_client.rb +20 -0
  66. data/lib/instana/activators/grpc_server.rb +20 -0
  67. data/lib/instana/activators/mongo.rb +23 -0
  68. data/lib/instana/activators/net_http.rb +20 -0
  69. data/lib/instana/activators/rack.rb +16 -0
  70. data/lib/instana/activators/rails.rb +18 -0
  71. data/lib/instana/activators/redis.rb +20 -0
  72. data/lib/instana/activators/resque_client.rb +21 -0
  73. data/lib/instana/activators/resque_worker.rb +32 -0
  74. data/lib/instana/activators/rest_client.rb +20 -0
  75. data/lib/instana/activators/roda.rb +21 -0
  76. data/lib/instana/activators/shoryuken.rb +24 -0
  77. data/lib/instana/activators/sidekiq_client.rb +24 -0
  78. data/lib/instana/activators/sidekiq_worker.rb +24 -0
  79. data/lib/instana/activators/sinatra.rb +21 -0
  80. data/lib/instana/backend/agent.rb +68 -0
  81. data/lib/instana/backend/gc_snapshot.rb +41 -0
  82. data/lib/instana/backend/host_agent.rb +83 -0
  83. data/lib/instana/backend/host_agent_activation_observer.rb +99 -0
  84. data/lib/instana/backend/host_agent_lookup.rb +57 -0
  85. data/lib/instana/backend/host_agent_reporting_observer.rb +129 -0
  86. data/lib/instana/backend/process_info.rb +72 -0
  87. data/lib/instana/backend/request_client.rb +74 -0
  88. data/lib/instana/backend/serverless_agent.rb +116 -0
  89. data/lib/instana/base.rb +15 -29
  90. data/lib/instana/config.rb +31 -23
  91. data/lib/instana/frameworks/cuba.rb +32 -3
  92. data/lib/instana/frameworks/rails.rb +22 -32
  93. data/lib/instana/frameworks/roda.rb +41 -3
  94. data/lib/instana/frameworks/sinatra.rb +16 -3
  95. data/lib/instana/instrumentation/action_cable.rb +53 -0
  96. data/lib/instana/instrumentation/action_controller.rb +84 -0
  97. data/lib/instana/instrumentation/action_mailer.rb +22 -0
  98. data/lib/instana/instrumentation/action_view.rb +30 -0
  99. data/lib/instana/instrumentation/active_job.rb +52 -0
  100. data/lib/instana/instrumentation/active_record.rb +50 -0
  101. data/lib/instana/instrumentation/aws_sdk_dynamodb.rb +48 -0
  102. data/lib/instana/instrumentation/aws_sdk_lambda.rb +37 -0
  103. data/lib/instana/instrumentation/aws_sdk_s3.rb +55 -0
  104. data/lib/instana/instrumentation/aws_sdk_sns.rb +29 -0
  105. data/lib/instana/instrumentation/aws_sdk_sqs.rb +98 -0
  106. data/lib/instana/instrumentation/dalli.rb +10 -18
  107. data/lib/instana/instrumentation/excon.rb +73 -61
  108. data/lib/instana/instrumentation/graphql.rb +78 -0
  109. data/lib/instana/instrumentation/grpc.rb +73 -66
  110. data/lib/instana/instrumentation/instrumented_request.rb +190 -0
  111. data/lib/instana/instrumentation/mongo.rb +46 -0
  112. data/lib/instana/instrumentation/net-http.rb +54 -44
  113. data/lib/instana/instrumentation/rack.rb +57 -48
  114. data/lib/instana/instrumentation/redis.rb +13 -18
  115. data/lib/instana/instrumentation/resque.rb +28 -51
  116. data/lib/instana/instrumentation/rest-client.rb +5 -17
  117. data/lib/instana/instrumentation/shoryuken.rb +44 -0
  118. data/lib/instana/instrumentation/sidekiq-client.rb +4 -10
  119. data/lib/instana/instrumentation/sidekiq-worker.rb +4 -10
  120. data/lib/instana/instrumented_logger.rb +26 -0
  121. data/lib/instana/logger_delegator.rb +31 -0
  122. data/lib/instana/open_tracing/carrier.rb +7 -0
  123. data/lib/instana/open_tracing/instana_tracer.rb +99 -0
  124. data/lib/instana/rack.rb +4 -0
  125. data/lib/instana/secrets.rb +59 -0
  126. data/lib/instana/serverless.rb +160 -0
  127. data/lib/instana/setup.rb +36 -12
  128. data/lib/instana/snapshot/deltable.rb +25 -0
  129. data/lib/instana/snapshot/docker_container.rb +151 -0
  130. data/lib/instana/snapshot/fargate_container.rb +88 -0
  131. data/lib/instana/snapshot/fargate_process.rb +67 -0
  132. data/lib/instana/snapshot/fargate_task.rb +72 -0
  133. data/lib/instana/snapshot/google_cloud_run_instance.rb +69 -0
  134. data/lib/instana/snapshot/google_cloud_run_process.rb +58 -0
  135. data/lib/instana/snapshot/lambda_function.rb +39 -0
  136. data/lib/instana/snapshot/ruby_process.rb +48 -0
  137. data/lib/instana/tracer.rb +42 -148
  138. data/lib/instana/tracing/processor.rb +48 -21
  139. data/lib/instana/tracing/span.rb +70 -61
  140. data/lib/instana/tracing/span_context.rb +34 -2
  141. data/lib/instana/util.rb +25 -137
  142. data/lib/instana/version.rb +4 -1
  143. data/lib/instana.rb +12 -2
  144. data/lib/opentracing.rb +29 -3
  145. data/sonar-project.properties +9 -0
  146. data/test/activator_test.rb +30 -0
  147. data/test/backend/agent_test.rb +80 -0
  148. data/test/backend/gc_snapshot_test.rb +11 -0
  149. data/test/backend/host_agent_activation_observer_test.rb +73 -0
  150. data/test/backend/host_agent_lookup_test.rb +78 -0
  151. data/test/backend/host_agent_reporting_observer_test.rb +274 -0
  152. data/test/backend/host_agent_test.rb +57 -0
  153. data/test/backend/process_info_test.rb +83 -0
  154. data/test/backend/request_client_test.rb +39 -0
  155. data/test/backend/serverless_agent_test.rb +83 -0
  156. data/test/benchmarks/bench_id_generation.rb +3 -0
  157. data/test/benchmarks/bench_opentracing.rb +3 -0
  158. data/test/config_test.rb +11 -14
  159. data/test/frameworks/cuba_test.rb +44 -30
  160. data/test/frameworks/roda_test.rb +46 -30
  161. data/test/frameworks/sinatra_test.rb +52 -30
  162. data/test/instana_test.rb +14 -4
  163. data/test/instrumentation/aws_test.rb +196 -0
  164. data/test/instrumentation/dalli_test.rb +3 -0
  165. data/test/instrumentation/excon_test.rb +20 -3
  166. data/test/instrumentation/graphql_test.rb +119 -0
  167. data/test/instrumentation/grpc_test.rb +6 -2
  168. data/test/instrumentation/mongo_test.rb +37 -0
  169. data/test/instrumentation/{net-http_test.rb → net_http_test.rb} +40 -0
  170. data/test/instrumentation/rack_instrumented_request_test.rb +151 -0
  171. data/test/instrumentation/rack_test.rb +404 -0
  172. data/test/instrumentation/rails_action_cable_test.rb +131 -0
  173. data/test/{frameworks/rails/actioncontroller_test.rb → instrumentation/rails_action_controller_test.rb} +48 -17
  174. data/test/instrumentation/rails_action_mailer_test.rb +37 -0
  175. data/test/instrumentation/rails_action_view_test.rb +151 -0
  176. data/test/instrumentation/rails_active_job_test.rb +65 -0
  177. data/test/instrumentation/rails_active_record_database_missing_test.rb +43 -0
  178. data/test/instrumentation/rails_active_record_test.rb +115 -0
  179. data/test/instrumentation/redis_test.rb +13 -0
  180. data/test/instrumentation/resque_test.rb +63 -17
  181. data/test/instrumentation/{rest-client_test.rb → rest_client_test.rb} +9 -0
  182. data/test/instrumentation/shoryuken_test.rb +47 -0
  183. data/test/instrumentation/sidekiq-client_test.rb +4 -0
  184. data/test/instrumentation/sidekiq-worker_test.rb +4 -0
  185. data/test/secrets_test.rb +112 -0
  186. data/test/serverless_test.rb +369 -0
  187. data/test/snapshot/deltable_test.rb +17 -0
  188. data/test/snapshot/docker_container_test.rb +82 -0
  189. data/test/snapshot/fargate_container_test.rb +82 -0
  190. data/test/snapshot/fargate_process_test.rb +35 -0
  191. data/test/snapshot/fargate_task_test.rb +49 -0
  192. data/test/snapshot/google_cloud_run_instance_test.rb +74 -0
  193. data/test/snapshot/google_cloud_run_process_test.rb +33 -0
  194. data/test/snapshot/lambda_function_test.rb +37 -0
  195. data/test/snapshot/ruby_process_test.rb +14 -0
  196. data/test/support/apps/active_record/active_record.rb +24 -0
  197. data/test/{servers/grpc_50051.rb → support/apps/grpc/boot.rb} +4 -1
  198. data/test/{apps → support/apps/grpc}/grpc_server.rb +3 -0
  199. data/test/{servers/rackapp_6511.rb → support/apps/http_endpoint/boot.rb} +3 -0
  200. data/test/{servers/rails_3205.rb → support/apps/rails/boot.rb} +10 -13
  201. data/test/{models → support/apps/rails/models}/block.rb +4 -1
  202. data/test/{models → support/apps/rails/models}/block6.rb +3 -0
  203. data/test/support/apps/resque/boot.rb +5 -0
  204. data/test/{jobs → support/apps/resque/jobs}/resque_error_job.rb +3 -3
  205. data/test/{jobs → support/apps/resque/jobs}/resque_fast_job.rb +6 -3
  206. data/test/support/apps/sidekiq/boot.rb +25 -0
  207. data/test/{jobs → support/apps/sidekiq/jobs}/sidekiq_job_1.rb +3 -0
  208. data/test/{jobs → support/apps/sidekiq/jobs}/sidekiq_job_2.rb +3 -0
  209. data/test/{servers → support/apps}/sidekiq/worker.rb +5 -2
  210. data/test/support/helpers.rb +97 -0
  211. data/test/support/mock_timer.rb +20 -0
  212. data/test/test_helper.rb +49 -145
  213. data/test/tracing/custom_test.rb +4 -4
  214. data/test/tracing/id_management_test.rb +13 -63
  215. data/test/tracing/instrumented_logger_test.rb +39 -0
  216. data/test/tracing/opentracing_test.rb +21 -5
  217. data/test/tracing/processor_test.rb +58 -0
  218. data/test/tracing/span_context_test.rb +22 -0
  219. data/test/tracing/span_test.rb +165 -0
  220. data/test/tracing/tracer_async_test.rb +32 -0
  221. data/test/tracing/tracer_test.rb +113 -14
  222. data/test/util_test.rb +10 -0
  223. metadata +249 -160
  224. data/.travis.yml +0 -43
  225. data/Dockerfile +0 -16
  226. data/benchmarks/10k-rack-traces.rb +0 -92
  227. data/benchmarks/Gemfile +0 -7
  228. data/benchmarks/Gemfile.lock +0 -38
  229. data/benchmarks/id_generation.rb +0 -12
  230. data/benchmarks/opentracing.rb +0 -26
  231. data/benchmarks/rack_vanilla_vs_traced.rb +0 -85
  232. data/benchmarks/stackprof_rack_tracing.rb +0 -77
  233. data/benchmarks/time_processing.rb +0 -12
  234. data/gemfiles/libraries.gemfile +0 -71
  235. data/gemfiles/rails32.gemfile +0 -51
  236. data/gemfiles/rails42.gemfile +0 -50
  237. data/gemfiles/rails50.gemfile +0 -52
  238. data/gemfiles/rails52.gemfile +0 -52
  239. data/gemfiles/rails60.gemfile +0 -72
  240. data/lib/instana/agent/helpers.rb +0 -84
  241. data/lib/instana/agent/hooks.rb +0 -41
  242. data/lib/instana/agent/tasks.rb +0 -48
  243. data/lib/instana/agent.rb +0 -499
  244. data/lib/instana/collector.rb +0 -116
  245. data/lib/instana/collectors/gc.rb +0 -57
  246. data/lib/instana/collectors/memory.rb +0 -34
  247. data/lib/instana/collectors/thread.rb +0 -30
  248. data/lib/instana/eum/eum-test.js.erb +0 -17
  249. data/lib/instana/eum/eum.js.erb +0 -17
  250. data/lib/instana/frameworks/instrumentation/abstract_mysql_adapter.rb +0 -58
  251. data/lib/instana/frameworks/instrumentation/action_controller.rb +0 -183
  252. data/lib/instana/frameworks/instrumentation/action_view.rb +0 -43
  253. data/lib/instana/frameworks/instrumentation/active_record.rb +0 -27
  254. data/lib/instana/frameworks/instrumentation/mysql2_adapter.rb +0 -81
  255. data/lib/instana/frameworks/instrumentation/mysql_adapter.rb +0 -56
  256. data/lib/instana/frameworks/instrumentation/postgresql_adapter.rb +0 -85
  257. data/lib/instana/helpers.rb +0 -44
  258. data/lib/instana/instrumentation.rb +0 -25
  259. data/lib/instana/opentracing/carrier.rb +0 -4
  260. data/lib/instana/opentracing/tracer.rb +0 -18
  261. data/lib/instana/test.rb +0 -42
  262. data/lib/instana/thread_local.rb +0 -15
  263. data/lib/oj_check.rb +0 -16
  264. data/test/agent/agent_test.rb +0 -148
  265. data/test/apps/cuba.rb +0 -15
  266. data/test/apps/roda.rb +0 -10
  267. data/test/apps/sinatra.rb +0 -5
  268. data/test/frameworks/rack_test.rb +0 -200
  269. data/test/frameworks/rails/actionview3_test.rb +0 -210
  270. data/test/frameworks/rails/actionview4_test.rb +0 -208
  271. data/test/frameworks/rails/actionview5_test.rb +0 -221
  272. data/test/frameworks/rails/activerecord_test.rb +0 -227
  273. data/test/servers/helpers/sidekiq_worker_initializer.rb +0 -27
  274. data/test/tracing/trace_test.rb +0 -67
data/lib/instana/agent.rb DELETED
@@ -1,499 +0,0 @@
1
- require 'net/http'
2
- require 'socket'
3
- require 'sys/proctable'
4
- require 'timers'
5
- require 'uri'
6
- require 'thread'
7
-
8
- require 'instana/agent/helpers'
9
- require 'instana/agent/hooks'
10
- require 'instana/agent/tasks'
11
-
12
- include Sys
13
-
14
- module Instana
15
- OJ_OPTIONS = {:mode => :strict}
16
-
17
- class Agent
18
- include AgentHelpers
19
- include AgentHooks
20
- include AgentTasks
21
-
22
- attr_accessor :state
23
- attr_accessor :agent_uuid
24
- attr_accessor :process
25
- attr_accessor :collect_thread
26
- attr_accessor :thread_spawn_lock
27
- attr_accessor :extra_headers
28
-
29
- attr_accessor :testmode
30
-
31
- LOCALHOST = '127.0.0.1'.freeze
32
- MIME_JSON = 'application/json'.freeze
33
- DISCOVERY_PATH = 'com.instana.plugin.ruby.discovery'.freeze
34
- METRICS_PATH = "com.instana.plugin.ruby.%s"
35
- TRACES_PATH = "com.instana.plugin.ruby/traces.%s"
36
-
37
- def initialize
38
- @testmode = ENV.key?('INSTANA_TEST')
39
-
40
- # Supported two states (unannounced & announced)
41
- @state = :unannounced
42
-
43
- # Timestamp of the last successful response from
44
- # entity data reporting.
45
- @entity_last_seen = Time.now
46
-
47
- # Used to track the last time the collect timer was run.
48
- @last_collect_run = Time.now
49
-
50
- # Two timers, one for each state (unannounced & announced)
51
- @timers = ::Timers::Group.new
52
- @announce_timer = nil
53
- @pending_timer = nil
54
- @collect_timer = nil
55
-
56
- @thread_spawn_lock = Mutex.new
57
-
58
- # Detect platform flags
59
- @is_linux = (RbConfig::CONFIG['host_os'] =~ /linux/i) ? true : false
60
- @is_osx = (RUBY_PLATFORM =~ /darwin/i) ? true : false
61
-
62
- # In case we're running in Docker, have the default gateway available
63
- # to check in case we're running in bridged network mode
64
- if @is_linux && File.exist?("/sbin/ip")
65
- @default_gateway = `/sbin/ip route | awk '/default/ { print $3 }'`.chomp
66
- else
67
- @default_gateway = nil
68
- end
69
-
70
- # Re-useable HTTP client for communication with
71
- # the host agent.
72
- @httpclient = nil
73
-
74
- # Collect initial process info - repeat prior to announce
75
- # in `announce_sensor` in case of process rename, after fork etc.
76
- @process = ::Instana::Util.collect_process_info
77
-
78
- # The agent UUID returned from the host agent
79
- @agent_uuid = nil
80
-
81
- # This will hold info on the discovered agent host
82
- @discovered = nil
83
-
84
- # The agent may pass down custom headers for this sensor to capture
85
- @extra_headers = nil
86
- end
87
-
88
- # Spawns the background thread and calls start. This method is separated
89
- # out for those who wish to control which thread the background agent will
90
- # run in.
91
- #
92
- # This method can be overridden with the following:
93
- #
94
- # module Instana
95
- # class Agent
96
- # def spawn_background_thread
97
- # # start thread
98
- # start
99
- # end
100
- # end
101
- # end
102
- #
103
- def spawn_background_thread
104
- @thread_spawn_lock.synchronize {
105
- if @collect_thread && @collect_thread.alive?
106
- ::Instana.logger.info "[instana] Collect thread already started & alive. Not spawning another."
107
- else
108
- @collect_thread = Thread.new do
109
- start
110
- end
111
- end
112
- }
113
- end
114
-
115
- # Sets up periodic timers and starts the agent in a background thread.
116
- #
117
- # There are three possible states for the agent:
118
- # - :unannounced
119
- # - :announced
120
- # - :ready
121
- def setup
122
- if ENV.key?('INSTANA_DISABLE')
123
- ::Instana.logger.info "Instana gem disabled via environment variable (INSTANA_DISABLE). Going to sit in a corner..."
124
- end
125
-
126
- # The announce timer
127
- # We attempt to announce this ruby sensor to the host agent.
128
- # In case of failure, we try again in 30 seconds.
129
- @announce_timer = @timers.now_and_every(30) do
130
- if @state == :unannounced && !ENV.key?('INSTANA_DISABLE')
131
- if host_agent_available? && announce_sensor
132
- transition_to(:announced)
133
- ::Instana.logger.debug "Announce successful. Waiting on ready. (#{@state} pid:#{Process.pid} #{@process[:name]})"
134
- end
135
- end
136
- end
137
-
138
- # The pending timer
139
- # Handles the time between successful announce and when the host agent METRICS_PATH and TRACES_PATH
140
- # no longer return 404s and are truly ready to accept data.
141
- @pending_timer = @timers.now_and_every(1) do
142
- path = sprintf(METRICS_PATH, @process[:report_pid])
143
- uri = URI.parse("http://#{::Instana.config[:agent_host]}:#{::Instana.config[:agent_port]}/#{path}")
144
- req = Net::HTTP::Post.new(uri)
145
- req.body = Oj.dump({}, OJ_OPTIONS)
146
-
147
- response = make_host_agent_request(req)
148
- if response && (response.code.to_i == 200)
149
- transition_to(:ready)
150
- ::Instana.logger.info "Host agent available. We're in business. (#{@state} pid:#{Process.pid} #{@process[:name]})"
151
- end
152
- end
153
-
154
- # The collect timer
155
- # If we are in announced state, send metric data (only delta reporting)
156
- # every ::Instana.config[:collector][:interval] seconds.
157
- @collect_timer = @timers.every(::Instana.config[:collector][:interval]) do
158
- # Make sure that this block doesn't get called more often than the interval. This can
159
- # happen on high CPU load and a back up of timer runs. If we are called before `interval`
160
- # then we just skip.
161
- unless (Time.now - @last_collect_run) < ::Instana.config[:collector][:interval]
162
- @last_collect_run = Time.now
163
- if @state == :ready
164
- if !::Instana.collector.collect_and_report
165
- # If report has been failing for more than 1 minute,
166
- # fall back to unannounced state
167
- if (Time.now - @entity_last_seen) > 60
168
- ::Instana.logger.warn "Host agent offline for >1 min. Going to sit in a corner..."
169
- transition_to(:unannounced)
170
- end
171
- end
172
- ::Instana.processor.send
173
- end
174
- end
175
- end
176
- end
177
-
178
- # Starts the timer loop for the timers that were initialized
179
- # in the setup method. This is blocking and should only be
180
- # called from an already initialized background thread.
181
- #
182
- def start
183
- if !ENV.key?('INSTANA_DISABLE') && !host_agent_available?
184
- if !ENV.key?("INSTANA_QUIET")
185
- ::Instana.logger.info "Instana host agent not available. Will retry periodically. (Set env INSTANA_QUIET=1 to shut these messages off)"
186
- end
187
- end
188
-
189
- while true
190
- if @state == :unannounced
191
- @announce_timer.resume
192
- @pending_timer.pause
193
- @collect_timer.pause
194
- elsif @state == :announced
195
- @announce_timer.pause
196
- @pending_timer.resume
197
- @collect_timer.pause
198
- elsif @state == :ready
199
- @announce_timer.pause
200
- @pending_timer.pause
201
- @collect_timer.resume
202
- end
203
- @timers.wait
204
- end
205
- rescue Exception => e
206
- ::Instana.logger.warn { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
207
- ::Instana.logger.debug { e.backtrace.join("\r\n") }
208
- ensure
209
- if @state == :ready
210
- # Pause the timers so they don't fire while we are reporting traces
211
- @announce_timer.pause
212
- @pending_timer.pause
213
- @collect_timer.pause
214
-
215
- ::Instana.logger.debug { "#{Thread.current}: Agent exiting. Reporting final spans (if any)." }
216
- ::Instana.processor.send
217
- end
218
- end
219
-
220
- # Collect process ID, name and arguments to notify
221
- # the host agent.
222
- #
223
- def announce_sensor
224
- unless @discovered
225
- ::Instana.logger.debug("#{__method__} called but discovery hasn't run yet!")
226
- return false
227
- end
228
-
229
- # Always re-collect process info before announce in case the process name has been
230
- # re-written (looking at you puma!)
231
- @process = ::Instana::Util.collect_process_info
232
-
233
- announce_payload = {}
234
- announce_payload[:name] = @process[:name]
235
- announce_payload[:args] = @process[:arguments]
236
-
237
- socket = nil
238
- if @is_linux && !@testmode
239
- # We create an open socket to the host agent in case we are running in a container
240
- # and the real pid needs to be detected.
241
- socket = TCPSocket.open @discovered[:agent_host], @discovered[:agent_port]
242
-
243
- announce_payload[:fd] = socket.fileno
244
- announce_payload[:inode] = File.readlink("/proc/self/fd/#{socket.fileno}")
245
- announce_payload[:cpuSetFileContent] = get_cpuset_contents
246
-
247
- sched_pid = get_sched_pid
248
- announce_payload[:pid] = sched_pid
249
-
250
- if running_in_container?
251
- if sched_pid != Process.pid
252
- # In container: sched reveals true PID
253
- announce_payload[:pidFromParentNS] = true
254
- else
255
- # In container: sched told us nothing
256
- announce_payload[:pidFromParentNS] = false
257
- end
258
- else
259
- # Not in a container
260
- announce_payload[:pidFromParentNS] = true
261
- end
262
-
263
- else
264
- announce_payload[:pid] = Process.pid
265
- announce_payload[:pidFromParentNS] = true
266
- end
267
-
268
- uri = URI.parse("http://#{@discovered[:agent_host]}:#{@discovered[:agent_port]}/#{DISCOVERY_PATH}")
269
- req = Net::HTTP::Put.new(uri)
270
- req.body = Oj.dump(announce_payload, OJ_OPTIONS)
271
-
272
- #::Instana.logger.debug("Announce payload: #{announce_payload}")
273
- #::Instana.logger.debug { "Announce: http://#{@discovered[:agent_host]}:#{@discovered[:agent_port]}/#{DISCOVERY_PATH} - payload: #{req.body}" }
274
-
275
- response = make_host_agent_request(req, open_timeout=3, read_timeout=3, debug=true)
276
-
277
- if response && (response.code.to_i == 200)
278
- data = Oj.load(response.body, OJ_OPTIONS)
279
- @process[:report_pid] = data['pid']
280
- @agent_uuid = data['agentUuid']
281
-
282
- if data.key?('extraHeaders')
283
- @extra_headers = data['extraHeaders']
284
- end
285
- true
286
- else
287
- false
288
- end
289
- rescue => e
290
- Instana.logger.info { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
291
- Instana.logger.debug { e.backtrace.join("\r\n") }
292
- return false
293
- ensure
294
- socket.close if socket && !socket.closed?
295
- end
296
-
297
- # Method to report metrics data to the host agent.
298
- #
299
- # @param paylod [Hash] The collection of metrics to report.
300
- #
301
- # @return [Boolean] true on success, false otherwise
302
- #
303
- def report_metrics(payload)
304
- if @state != :ready && !@testmode
305
- ::Instana.logger.debug "report_metrics called but agent not in ready state."
306
- return false
307
- end
308
-
309
- path = sprintf(METRICS_PATH, @process[:report_pid])
310
- uri = URI.parse("http://#{@discovered[:agent_host]}:#{@discovered[:agent_port]}/#{path}")
311
- req = Net::HTTP::Post.new(uri)
312
-
313
- req.body = Oj.dump(payload, OJ_OPTIONS)
314
- response = make_host_agent_request(req)
315
-
316
- if response
317
- if response.body && response.body.length > 2
318
- # The host agent returned something indicating that is has a request for us that we
319
- # need to process.
320
- handle_agent_tasks(response.body)
321
- end
322
-
323
- if response.code.to_i == 200
324
- @entity_last_seen = Time.now
325
- return true
326
- end
327
-
328
- end
329
- false
330
- rescue => e
331
- Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
332
- Instana.logger.debug { e.backtrace.join("\r\n") }
333
- end
334
-
335
- # Accept and report spans to the host agent.
336
- #
337
- # @param spans [Array] An array of [Span]
338
- # @return [Boolean]
339
- #
340
- def report_spans(spans)
341
- if @state != :ready && !@testmode
342
- ::Instana.logger.debug "report_spans called but agent not in ready state."
343
- return false
344
- end
345
-
346
- ::Instana.logger.debug "Reporting #{spans.length} spans"
347
-
348
- path = sprintf(TRACES_PATH, @process[:report_pid])
349
- uri = URI.parse("http://#{@discovered[:agent_host]}:#{@discovered[:agent_port]}/#{path}")
350
- req = Net::HTTP::Post.new(uri)
351
-
352
- opts = OJ_OPTIONS.merge({omit_nil: true})
353
-
354
- req.body = Oj.dump(spans, opts)
355
- response = make_host_agent_request(req)
356
-
357
- if response
358
- last_trace_response = response.code.to_i
359
-
360
- if [200, 204].include?(last_trace_response)
361
- return true
362
- end
363
- end
364
- false
365
- rescue => e
366
- Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
367
- Instana.logger.debug { e.backtrace.join("\r\n") }
368
- end
369
-
370
- # Check that the host agent is available and can be contacted. This will
371
- # first check localhost and if not, then attempt on the default gateway
372
- # for docker in bridged mode.
373
- #
374
- def host_agent_available?
375
- @discovered ||= run_discovery
376
-
377
- if @discovered
378
- return true
379
- end
380
- false
381
- rescue => e
382
- Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
383
- Instana.logger.debug { e.backtrace.join("\r\n") } unless @testmode
384
- return false
385
- end
386
-
387
- # Runs a discovery process to determine where we can contact the host agent. This is usually just
388
- # localhost but in docker can be found on the default gateway. Another option is the INSTANA_AGENT_HOST
389
- # environment variable. This also allows for manual configuration via ::Instana.config[:agent_host/port].
390
- #
391
- # @return [Hash] a hash with :agent_host, :agent_port values or empty hash
392
- #
393
- def run_discovery
394
- discovered = {}
395
-
396
- ::Instana.logger.debug { "#{__method__}: Running agent discovery..." }
397
-
398
- # Try default location or manually configured (if so)
399
- uri = URI.parse("http://#{::Instana.config[:agent_host]}:#{::Instana.config[:agent_port]}/")
400
- req = Net::HTTP::Get.new(uri)
401
-
402
- ::Instana.logger.debug { "#{__method__}: Trying #{::Instana.config[:agent_host]}:#{::Instana.config[:agent_port]}" }
403
-
404
- response = make_host_agent_request(req)
405
-
406
- if response && (response.code.to_i == 200)
407
- discovered[:agent_host] = ::Instana.config[:agent_host]
408
- discovered[:agent_port] = ::Instana.config[:agent_port]
409
- ::Instana.logger.debug { "#{__method__}: Found #{discovered[:agent_host]}:#{discovered[:agent_port]}" }
410
- return discovered
411
- end
412
-
413
- return nil unless @is_linux
414
-
415
- # We are potentially running on Docker in bridged networking mode.
416
- # Attempt to contact default gateway
417
- uri = URI.parse("http://#{@default_gateway}:#{::Instana.config[:agent_port]}/")
418
- req = Net::HTTP::Get.new(uri)
419
-
420
- ::Instana.logger.debug { "#{__method__}: Trying default gateway #{@default_gateway}:#{::Instana.config[:agent_port]}" }
421
-
422
- response = make_host_agent_request(req)
423
-
424
- if response && (response.code.to_i == 200)
425
- discovered[:agent_host] = @default_gateway
426
- discovered[:agent_port] = ::Instana.config[:agent_port]
427
- ::Instana.logger.debug { "#{__method__}: Found #{discovered[:agent_host]}:#{discovered[:agent_port]}" }
428
- return discovered
429
- end
430
-
431
- nil
432
- end
433
-
434
- private
435
-
436
- # Handles any/all steps required in the transtion
437
- # between states.
438
- #
439
- # @param state [Symbol] Can be 1 of 2 possible states:
440
- # `:announced`, `:unannounced`
441
- #
442
- def transition_to(state)
443
- ::Instana.logger.debug("Transitioning to #{state}")
444
- case state
445
- when :ready
446
- # announced
447
- @state = :ready
448
-
449
- # Reset the entity timer
450
- @entity_last_seen = Time.now
451
- when :announced
452
- # announce successful; set state
453
- @state = :announced
454
-
455
- # Reset the entity timer
456
- @entity_last_seen = Time.now
457
- when :unannounced
458
- @state = :unannounced
459
- # Reset our HTTP client
460
- @httpclient = nil
461
- else
462
- ::Instana.logger.debug "Uknown agent state: #{state}"
463
- end
464
- ::Instana.collector.reset_snapshot_timer!
465
- true
466
- end
467
-
468
- # Centralization of the net/http communications
469
- # with the host agent. Pass in a prepared <req>
470
- # of type Net::HTTP::Get|Put|Head
471
- #
472
- # @param req [Net::HTTP::Req] A prepared Net::HTTP request object of the type
473
- # you wish to make (Get, Put, Post etc.)
474
- #
475
- def make_host_agent_request(req, open_timeout=1, read_timeout=1, debug=false)
476
- req['Accept'] = MIME_JSON
477
- req['Content-Type'] = MIME_JSON
478
-
479
- if @state == :unannounced
480
- @httpclient = Net::HTTP.new(req.uri.hostname, req.uri.port)
481
- @httpclient.open_timeout = open_timeout
482
- @httpclient.read_timeout = read_timeout
483
- end
484
-
485
- response = @httpclient.request(req)
486
-
487
- if debug
488
- ::Instana.logger.debug "#{req.method}->#{req.uri} body:(#{req.body}) Response:#{response} body:(#{response.body})"
489
- end
490
-
491
- response
492
- rescue Errno::ECONNREFUSED
493
- return nil
494
- rescue => e
495
- Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message} (to #{req.uri})" }
496
- return nil
497
- end
498
- end
499
- end
@@ -1,116 +0,0 @@
1
- module Instana
2
- class Collector
3
- attr_accessor :collectors
4
- attr_accessor :last_report_log
5
-
6
- def initialize
7
- @collectors = []
8
-
9
- # Snapshot data is collected once per process but resent
10
- # every 10 minutes along side process metrics.
11
- @snapshot = ::Instana::Util.take_snapshot
12
-
13
- # Set last snapshot to just under 10 minutes ago
14
- # so we send a snapshot sooner than later
15
- @last_snapshot = Time.now - 570
16
-
17
- # We track what we last sent as a metric payload so that
18
- # we can do delta reporting
19
- @last_values = {}
20
- end
21
-
22
- # Register an individual collector.
23
- #
24
- # @param [Object] klass of the collector to register
25
- #
26
- def register(klass)
27
- ::Instana.logger.debug "Adding #{klass} to collectors..."
28
- @collectors << klass.new
29
- end
30
-
31
- # Resets the timer on when to send process snapshot data.
32
- #
33
- def reset_snapshot_timer!
34
- # Set last snapshot to 10 minutes ago
35
- # so that we send a snapshot on first report
36
- @last_snapshot = Time.now - 601
37
- end
38
-
39
- ##
40
- # collect_and_report
41
- #
42
- # Run through each collector, let them collect up
43
- # data and then report what we have via the agent
44
- #
45
- # @return Boolean true on success
46
- #
47
- def collect_and_report
48
- return unless ::Instana.config[:metrics][:enabled]
49
-
50
- payload = {}
51
- with_snapshot = false
52
-
53
- # Run through the registered collectors and
54
- # get all the metrics
55
- #
56
- @collectors.each do |c|
57
- metrics = c.collect
58
- if metrics
59
- payload[c.payload_key] = metrics
60
- else
61
- payload.delete(c.payload_key)
62
- end
63
- end
64
-
65
- # Every 5 minutes, send snapshot data as well
66
- if (Time.now - @last_snapshot) > 600
67
- with_snapshot = true
68
- payload.merge!(@snapshot)
69
-
70
- # Add in process related that could have changed since
71
- # snapshot was taken.
72
- p = { :pid => ::Instana.agent.report_pid }
73
- p[:name] = ::Instana::Util.get_app_name
74
- p[:exec_args] = ::Instana.agent.process[:arguments]
75
- payload.merge!(p)
76
- else
77
- payload = enforce_deltas(payload, @last_values)
78
- end
79
-
80
- if ENV.key?('INSTANA_TEST')
81
- true
82
- else
83
- # Report all the collected goodies
84
- if ::Instana.agent.report_metrics(payload) && with_snapshot
85
- @last_snapshot = Time.now
86
- end
87
- end
88
- end
89
-
90
- # Take two hashes and enforce delta reporting.
91
- # We only report when values change (instead of reporting all of
92
- # the time). This is a recursive method.
93
- #
94
- # @param [Hash] the payload have delta reporting applied to
95
- # @param [Hash] a hash of the last values reported
96
- #
97
- # @return [Hash] the candidate hash with delta reporting applied
98
- #
99
- def enforce_deltas(candidate, last)
100
- candidate.each do |k,v|
101
- if v.is_a?(Hash)
102
- last[k] ||= {}
103
- candidate[k] = enforce_deltas(candidate[k], last[k])
104
- candidate.delete(k) if candidate[k].empty?
105
- else
106
- if last[k] == v
107
- candidate.delete(k)
108
- else
109
- last[k] = candidate[k]
110
- end
111
- end
112
- end
113
- candidate
114
- end
115
- end
116
- end
@@ -1,57 +0,0 @@
1
- module Instana
2
- module Collectors
3
- class GC
4
- attr_accessor :payload_key
5
-
6
- def initialize
7
- @payload_key = :gc
8
- @this_gc = {}
9
- @last_major_count = 0
10
- @last_minor_count = 0
11
- ::GC::Profiler.enable
12
- end
13
-
14
- ##
15
- # collect
16
- #
17
- # To collect garbage collector related metrics.
18
- #
19
- def collect
20
- @this_gc.clear
21
- stats = ::GC.stat
22
-
23
- # Time spent in GC. Report in milliseconds
24
- @this_gc[:totalTime] = ::GC::Profiler.total_time * 1000
25
- ::GC::Profiler.clear
26
-
27
- # GC metrics only available on newer Ruby versions
28
- if RUBY_VERSION >= '2.1'
29
- # GC runs. Calculate how many have occurred since the last call
30
- @this_gc[:minorGcs] = stats[:minor_gc_count] - @last_minor_count
31
- @this_gc[:majorGcs] = stats[:major_gc_count] - @last_major_count
32
-
33
- # Store these counts so that we have something to compare to next
34
- # time around.
35
- @last_major_count = stats[:major_gc_count]
36
- @last_minor_count = stats[:minor_gc_count]
37
-
38
- @this_gc[:heap_live] = stats[:heap_live_slots] || stats[:heap_live_num]
39
- @this_gc[:heap_free] = stats[:heap_free_slots] || stats[:heap_free_num]
40
- else
41
- @this_gc[:heap_live] = stats[:heap_live_slot] || stats[:heap_live_num]
42
- @this_gc[:heap_free] = stats[:heap_free_slot] || stats[:heap_free_num]
43
- end
44
-
45
- @this_gc
46
- rescue => e
47
- ::Instana.logger.info "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
48
- ::Instana.logger.debug { e.backtrace.join("\r\n") }
49
- end
50
- end
51
- end
52
- end
53
-
54
- # Register the metrics collector if enabled
55
- if ::Instana.config[:metrics][:gc][:enabled]
56
- ::Instana.collector.register(::Instana::Collectors::GC)
57
- end
@@ -1,34 +0,0 @@
1
- require 'get_process_mem'
2
-
3
- module Instana
4
- module Collectors
5
- class Memory
6
- attr_accessor :payload_key
7
-
8
- def initialize
9
- @payload_key = :memory
10
- @this_mem = {}
11
- end
12
-
13
- ##
14
- # collect
15
- #
16
- # To collect process memory usage.
17
- #
18
- # @return [Hash] a collection of metrics (if any)
19
- #
20
- def collect
21
- @this_mem[:rss_size] = ::GetProcessMem.new(Process.pid).kb
22
- @this_mem
23
- rescue => e
24
- ::Instana.logger.info "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
25
- ::Instana.logger.debug { e.backtrace.join("\r\n") }
26
- end
27
- end
28
- end
29
- end
30
-
31
- # Register the metrics collector if enabled
32
- if ::Instana.config[:metrics][:memory][:enabled]
33
- ::Instana.collector.register(::Instana::Collectors::Memory)
34
- end