instana 1.10.1-java

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 (125) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +23 -0
  3. data/.gitignore +16 -0
  4. data/.rubocop.yml +1156 -0
  5. data/.travis.yml +43 -0
  6. data/Configuration.md +149 -0
  7. data/Dockerfile +13 -0
  8. data/Gemfile +41 -0
  9. data/LICENSE +21 -0
  10. data/README.md +102 -0
  11. data/Rakefile +56 -0
  12. data/Tracing.md +145 -0
  13. data/Troubleshooting.md +32 -0
  14. data/benchmarks/Gemfile +7 -0
  15. data/benchmarks/id_generation.rb +12 -0
  16. data/benchmarks/opentracing.rb +26 -0
  17. data/benchmarks/rack_vanilla_vs_traced.rb +80 -0
  18. data/benchmarks/stackprof_rack_tracing.rb +77 -0
  19. data/benchmarks/time_processing.rb +12 -0
  20. data/bin/console +7 -0
  21. data/bin/setup +8 -0
  22. data/examples/opentracing.rb +31 -0
  23. data/examples/tracing.rb +80 -0
  24. data/gemfiles/libraries.gemfile +71 -0
  25. data/gemfiles/rails32.gemfile +51 -0
  26. data/gemfiles/rails42.gemfile +50 -0
  27. data/gemfiles/rails50.gemfile +52 -0
  28. data/instana.gemspec +46 -0
  29. data/lib/instana.rb +12 -0
  30. data/lib/instana/agent.rb +441 -0
  31. data/lib/instana/agent/helpers.rb +61 -0
  32. data/lib/instana/agent/hooks.rb +37 -0
  33. data/lib/instana/agent/tasks.rb +48 -0
  34. data/lib/instana/base.rb +54 -0
  35. data/lib/instana/collector.rb +116 -0
  36. data/lib/instana/collectors/gc.rb +57 -0
  37. data/lib/instana/collectors/memory.rb +34 -0
  38. data/lib/instana/collectors/thread.rb +30 -0
  39. data/lib/instana/config.rb +79 -0
  40. data/lib/instana/eum/eum-test.js.erb +16 -0
  41. data/lib/instana/eum/eum.js.erb +14 -0
  42. data/lib/instana/frameworks/cuba.rb +6 -0
  43. data/lib/instana/frameworks/instrumentation/abstract_mysql_adapter.rb +58 -0
  44. data/lib/instana/frameworks/instrumentation/action_controller.rb +183 -0
  45. data/lib/instana/frameworks/instrumentation/action_view.rb +43 -0
  46. data/lib/instana/frameworks/instrumentation/active_record.rb +27 -0
  47. data/lib/instana/frameworks/instrumentation/mysql2_adapter.rb +81 -0
  48. data/lib/instana/frameworks/instrumentation/mysql_adapter.rb +56 -0
  49. data/lib/instana/frameworks/instrumentation/postgresql_adapter.rb +71 -0
  50. data/lib/instana/frameworks/rails.rb +42 -0
  51. data/lib/instana/frameworks/roda.rb +6 -0
  52. data/lib/instana/frameworks/sinatra.rb +9 -0
  53. data/lib/instana/helpers.rb +40 -0
  54. data/lib/instana/instrumentation.rb +21 -0
  55. data/lib/instana/instrumentation/dalli.rb +78 -0
  56. data/lib/instana/instrumentation/excon.rb +74 -0
  57. data/lib/instana/instrumentation/grpc.rb +84 -0
  58. data/lib/instana/instrumentation/net-http.rb +66 -0
  59. data/lib/instana/instrumentation/rack.rb +77 -0
  60. data/lib/instana/instrumentation/redis.rb +82 -0
  61. data/lib/instana/instrumentation/resque.rb +131 -0
  62. data/lib/instana/instrumentation/rest-client.rb +34 -0
  63. data/lib/instana/instrumentation/sidekiq-client.rb +45 -0
  64. data/lib/instana/instrumentation/sidekiq-worker.rb +54 -0
  65. data/lib/instana/opentracing/carrier.rb +4 -0
  66. data/lib/instana/opentracing/tracer.rb +18 -0
  67. data/lib/instana/rack.rb +10 -0
  68. data/lib/instana/setup.rb +36 -0
  69. data/lib/instana/test.rb +40 -0
  70. data/lib/instana/thread_local.rb +15 -0
  71. data/lib/instana/tracer.rb +392 -0
  72. data/lib/instana/tracing/processor.rb +92 -0
  73. data/lib/instana/tracing/span.rb +401 -0
  74. data/lib/instana/tracing/span_context.rb +33 -0
  75. data/lib/instana/util.rb +261 -0
  76. data/lib/instana/version.rb +4 -0
  77. data/lib/oj_check.rb +16 -0
  78. data/lib/opentracing.rb +6 -0
  79. data/test/agent/agent_test.rb +143 -0
  80. data/test/apps/cuba.rb +15 -0
  81. data/test/apps/grpc_server.rb +81 -0
  82. data/test/apps/roda.rb +10 -0
  83. data/test/apps/sinatra.rb +5 -0
  84. data/test/benchmarks/bench_id_generation.rb +12 -0
  85. data/test/benchmarks/bench_opentracing.rb +13 -0
  86. data/test/config_test.rb +37 -0
  87. data/test/frameworks/cuba_test.rb +44 -0
  88. data/test/frameworks/rack_test.rb +167 -0
  89. data/test/frameworks/rails/actioncontroller_test.rb +93 -0
  90. data/test/frameworks/rails/actionview3_test.rb +255 -0
  91. data/test/frameworks/rails/actionview4_test.rb +254 -0
  92. data/test/frameworks/rails/actionview5_test.rb +221 -0
  93. data/test/frameworks/rails/activerecord3_test.rb +134 -0
  94. data/test/frameworks/rails/activerecord4_test.rb +134 -0
  95. data/test/frameworks/rails/activerecord5_test.rb +87 -0
  96. data/test/frameworks/roda_test.rb +44 -0
  97. data/test/frameworks/sinatra_test.rb +44 -0
  98. data/test/instana_test.rb +27 -0
  99. data/test/instrumentation/dalli_test.rb +253 -0
  100. data/test/instrumentation/excon_test.rb +147 -0
  101. data/test/instrumentation/grpc_test.rb +377 -0
  102. data/test/instrumentation/net-http_test.rb +160 -0
  103. data/test/instrumentation/redis_test.rb +119 -0
  104. data/test/instrumentation/resque_test.rb +128 -0
  105. data/test/instrumentation/rest-client_test.rb +55 -0
  106. data/test/instrumentation/sidekiq-client_test.rb +125 -0
  107. data/test/instrumentation/sidekiq-worker_test.rb +173 -0
  108. data/test/jobs/resque_error_job.rb +22 -0
  109. data/test/jobs/resque_fast_job.rb +20 -0
  110. data/test/jobs/sidekiq_job_1.rb +6 -0
  111. data/test/jobs/sidekiq_job_2.rb +7 -0
  112. data/test/models/block.rb +18 -0
  113. data/test/servers/grpc_50051.rb +20 -0
  114. data/test/servers/helpers/sidekiq_worker_initializer.rb +27 -0
  115. data/test/servers/rackapp_6511.rb +25 -0
  116. data/test/servers/rails_3205.rb +167 -0
  117. data/test/servers/sidekiq/worker.rb +27 -0
  118. data/test/test_helper.rb +145 -0
  119. data/test/tracing/custom_test.rb +158 -0
  120. data/test/tracing/id_management_test.rb +130 -0
  121. data/test/tracing/opentracing_test.rb +335 -0
  122. data/test/tracing/trace_test.rb +67 -0
  123. data/test/tracing/tracer_async_test.rb +198 -0
  124. data/test/tracing/tracer_test.rb +223 -0
  125. metadata +327 -0
@@ -0,0 +1,61 @@
1
+ module AgentHelpers
2
+ # Indicates whether we are running in a pid namespace (such as
3
+ # Docker).
4
+ #
5
+ def pid_namespace?
6
+ return false unless @is_linux
7
+ Process.pid != get_real_pid
8
+ end
9
+
10
+ # Attempts to determine the true process ID by querying the
11
+ # /proc/<pid>/sched file. This works on linux currently.
12
+ #
13
+ def get_real_pid
14
+ raise RuntimeError.new("Unsupported platform: get_real_pid") unless @is_linux
15
+
16
+ sched_file = "/proc/#{Process.pid}/sched"
17
+ pid = Process.pid
18
+
19
+ if File.exist?(sched_file)
20
+ v = File.open(sched_file, &:readline)
21
+ pid = v.match(/\d+/).to_s.to_i
22
+ end
23
+ pid
24
+ end
25
+
26
+ # Returns the PID that we are reporting to
27
+ #
28
+ def report_pid
29
+ @process[:report_pid]
30
+ end
31
+
32
+ # Determine whether the pid has changed since Agent start.
33
+ #
34
+ # @ return [Boolean] true or false to indicate if forked
35
+ #
36
+ def forked?
37
+ @process[:pid] != Process.pid
38
+ end
39
+
40
+ # Indicates if the agent is ready to send metrics
41
+ # and/or data.
42
+ #
43
+ def ready?
44
+ # In test, we're always ready :-)
45
+ return true if ENV.key?('INSTANA_TEST')
46
+
47
+ # Occasionally Run Fork detection
48
+ if rand(10) > 8
49
+ if !@is_resque_worker && (@process[:pid] != Process.pid)
50
+ ::Instana.logger.debug "Instana: detected fork. (this pid: #{Process.pid}/#{Process.ppid}) Calling after_fork"
51
+ after_fork
52
+ end
53
+ end
54
+
55
+ @state == :announced
56
+ rescue => e
57
+ Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
58
+ Instana.logger.debug { e.backtrace.join("\r\n") } unless ENV.key?('INSTANA_TEST')
59
+ return false
60
+ end
61
+ end
@@ -0,0 +1,37 @@
1
+ module AgentHooks
2
+ # Used post fork to re-initialize state and restart communications with
3
+ # the host agent.
4
+ #
5
+ def after_fork
6
+ ::Instana.logger.debug "after_fork hook called. Falling back to unannounced state and spawning a new background agent thread."
7
+
8
+ # Reseed the random number generator for this
9
+ # new thread.
10
+ srand
11
+
12
+ transition_to(:unannounced)
13
+
14
+ setup
15
+ spawn_background_thread
16
+ end
17
+
18
+ def before_resque_fork
19
+ ::Instana.logger.debug "before_resque_fork hook called. pid/ppid: #{Process.pid}/#{Process.ppid}"
20
+ @is_resque_worker = true
21
+ end
22
+
23
+ def after_resque_fork
24
+ ::Instana.logger.debug "after_resque_fork hook called. pid/ppid: #{Process.pid}/#{Process.ppid}"
25
+
26
+ # Reseed the random number generator for this
27
+ # new thread.
28
+ srand
29
+
30
+ ::Instana.config[:metrics][:enabled] = false
31
+
32
+ @process[:pid] = Process.pid
33
+
34
+ setup
35
+ spawn_background_thread
36
+ end
37
+ end
@@ -0,0 +1,48 @@
1
+ module AgentTasks
2
+ # When request(s) are received by the host agent, it is sent here
3
+ # for handling & processing.
4
+ #
5
+ # @param json_string [String] the requests from the host agent
6
+ #
7
+
8
+ OJ_OPTIONS = {mode: :strict}
9
+
10
+ def handle_agent_tasks(json_string)
11
+ tasks = Oj.load(json_string, OJ_OPTIONS)
12
+
13
+ if tasks.is_a?(Hash)
14
+ process_agent_task(tasks)
15
+ elsif tasks.is_a?(Array)
16
+ tasks.each do |t|
17
+ process_agent_task(t)
18
+ end
19
+ end
20
+ end
21
+
22
+ # Process a task sent from the host agent.
23
+ #
24
+ # @param task [String] the request json from the host agent
25
+ #
26
+ def process_agent_task(task)
27
+ if task.key?("action")
28
+ if task["action"] == "ruby.source"
29
+ payload = ::Instana::Util.get_rb_source(task["args"]["file"])
30
+ else
31
+ payload = { :error => "Unrecognized action: #{task["action"]}. An newer Instana gem may be required for this. Current version: #{::Instana::VERSION}" }
32
+ end
33
+ else
34
+ payload = { :error => "Instana Ruby: No action specified in request." }
35
+ end
36
+
37
+ path = "com.instana.plugin.ruby/response.#{@process[:report_pid]}?messageId=#{URI.encode(task['messageId'])}"
38
+ uri = URI.parse("http://#{@discovered[:agent_host]}:#{@discovered[:agent_port]}/#{path}")
39
+ req = Net::HTTP::Post.new(uri)
40
+ req.body = Oj.dump(payload, OJ_OPTIONS)
41
+ ::Instana.logger.debug "Responding to agent request: #{req.inspect}"
42
+ make_host_agent_request(req)
43
+
44
+ rescue StandardError => e
45
+ Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
46
+ Instana.logger.debug { e.backtrace.join("\r\n") }
47
+ end
48
+ end
@@ -0,0 +1,54 @@
1
+ require "logger"
2
+ require "instana/version"
3
+ require "instana/util"
4
+ require "instana/helpers"
5
+
6
+ module Instana
7
+ class << self
8
+ attr_accessor :agent
9
+ attr_accessor :collector
10
+ attr_accessor :tracer
11
+ attr_accessor :processor
12
+ attr_accessor :config
13
+ attr_accessor :logger
14
+ attr_accessor :pid
15
+
16
+ ##
17
+ # setup
18
+ #
19
+ # Setup the Instana language agent to an informal "ready
20
+ # to run" state.
21
+ #
22
+ def setup
23
+ @agent = ::Instana::Agent.new
24
+ @tracer = ::Instana::Tracer.new
25
+ @processor = ::Instana::Processor.new
26
+ @collector = ::Instana::Collector.new
27
+ end
28
+ end
29
+ end
30
+
31
+ # Setup the logger as early as possible
32
+
33
+ # Default Logger outputs to STDOUT
34
+ ::Instana.logger = Logger.new(STDOUT)
35
+
36
+ # Can instead log to a file that is rotated every 10M
37
+ # ::Instana.logger = Logger.new("instana.log", 10, 1073741824)
38
+
39
+ if ENV.key?('INSTANA_GEM_TEST')
40
+ ::Instana.logger.level = Logger::DEBUG
41
+ elsif ENV.key?('INSTANA_GEM_DEV') || ENV.key?('INSTANA_DEBUG')
42
+ ::Instana.logger.level = Logger::DEBUG
43
+ elsif ENV.key?('INSTANA_QUIET')
44
+ ::Instana.logger.level = Logger::FATAL
45
+ else
46
+ ::Instana.logger.level = Logger::WARN
47
+ end
48
+
49
+ ::Instana.logger.formatter = proc do |severity, datetime, progname, msg|
50
+ "#{datetime}: #{severity.rjust(5)} Instana: #{progname} #{msg}\n"
51
+ end
52
+
53
+
54
+ ::Instana.logger.info "Stan is on the scene. Starting Instana instrumentation version #{::Instana::VERSION}"
@@ -0,0 +1,116 @@
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] the class 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_timer!
34
+ # Set last snapshot to 10 minutes ago
35
+ # so 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
@@ -0,0 +1,57 @@
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
@@ -0,0 +1,34 @@
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
@@ -0,0 +1,30 @@
1
+ module Instana
2
+ module Collectors
3
+ class Thread
4
+ attr_accessor :payload_key
5
+
6
+ def initialize
7
+ @payload_key = :thread
8
+ @this_count = {}
9
+ end
10
+
11
+ ##
12
+ # collect
13
+ #
14
+ # To collect thread count
15
+ #
16
+ def collect
17
+ @this_count[:count] = ::Thread.list.count
18
+ @this_count
19
+ rescue => e
20
+ ::Instana.logger.info "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
21
+ ::Instana.logger.debug { e.backtrace.join("\r\n") }
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ # Register the metrics collector if enabled
28
+ if ::Instana.config[:metrics][:thread][:enabled]
29
+ ::Instana.collector.register(::Instana::Collectors::Thread)
30
+ end