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,92 @@
1
+ require 'thread'
2
+
3
+ module Instana
4
+ class Processor
5
+ def initialize
6
+ # The main queue before being reported to the
7
+ # host agent. Spans in this queue are complete
8
+ # and ready to be sent.
9
+ @queue = Queue.new
10
+
11
+ # This is the maximum number of spans we send to the host
12
+ # agent at once.
13
+ @batch_size = 3000
14
+ end
15
+
16
+ # Adds a Set of spans to the queue
17
+ #
18
+ # @param [spans] - the trace to be added to the queue
19
+ def add_spans(spans)
20
+ spans.each { |span| @queue.push(span)}
21
+ end
22
+
23
+ # Adds a span to the span queue
24
+ #
25
+ # @param [Trace] - the trace to be added to the queue
26
+ def add_span(span)
27
+ # Occasionally, do a checkup on our background thread.
28
+ if rand(10) > 8
29
+ if ::Instana.agent.collect_thread.nil? || !::Instana.agent.collect_thread.alive?
30
+ ::Instana.agent.spawn_background_thread
31
+ end
32
+ end
33
+ @queue.push(span)
34
+ end
35
+
36
+ ##
37
+ # send
38
+ #
39
+ # Sends all traces in @queue to the host agent
40
+ #
41
+ # FIXME: Add limits checking here in regards to:
42
+ # - Max HTTP Post size
43
+ # - Out of control/growing queue
44
+ # - Prevent another run of the timer while this is running
45
+ #
46
+ def send
47
+ return if @queue.empty? || ENV.key?('INSTANA_TEST')
48
+
49
+ # Retrieve all spans for queued traces
50
+ spans = queued_spans
51
+
52
+ # Report spans in batches
53
+ batch = spans.shift(@batch_size)
54
+ while !batch.empty? do
55
+ ::Instana.agent.report_spans(batch)
56
+ batch = spans.shift(@batch_size)
57
+ end
58
+ end
59
+
60
+ # Retrieves all of the traces in @queue and returns
61
+ # the sum of their raw spans.
62
+ # This is used by Processor::send and in the test suite.
63
+ # Note that traces retrieved with this method are removed
64
+ # entirely from the queue.
65
+ #
66
+ # @return [Array] An array of [Span] or empty
67
+ #
68
+ def queued_spans
69
+ return [] if @queue.empty?
70
+
71
+ spans = []
72
+ until @queue.empty? do
73
+ # Non-blocking pop; ignore exception
74
+ span = @queue.pop(true) rescue nil
75
+ if span
76
+ spans << span.raw
77
+ end
78
+ end
79
+ spans
80
+ end
81
+
82
+ # Removes all traces from the @queue. Used in the
83
+ # test suite to reset state.
84
+ #
85
+ def clear!
86
+ until @queue.empty? do
87
+ # Non-blocking pop; ignore exception
88
+ @queue.pop(true) rescue nil
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,401 @@
1
+ module Instana
2
+ class Span
3
+ REGISTERED_SPANS = [ :actioncontroller, :actionview, :activerecord, :excon,
4
+ :memcache, :'net-http', :rack, :render, :'rpc-client',
5
+ :'rpc-server', :'sidekiq-client', :'sidekiq-worker',
6
+ :redis, :'resque-client', :'resque-worker' ].freeze
7
+ ENTRY_SPANS = [ :rack, :'resque-worker', :'rpc-server', :'sidekiq-worker' ].freeze
8
+ EXIT_SPANS = [ :activerecord, :excon, :'net-http', :'resque-client',
9
+ :'rpc-client', :'sidekiq-client', :redis ].freeze
10
+ HTTP_SPANS = [ :rack, :excon, :'net-http' ].freeze
11
+
12
+ attr_accessor :parent
13
+ attr_accessor :baggage
14
+ attr_accessor :is_root
15
+ attr_accessor :context
16
+
17
+ def initialize(name, parent_ctx: nil, start_time: ::Instana::Util.now_in_ms)
18
+ @data = {}
19
+
20
+ if parent_ctx == nil
21
+ # No parent specified so we're starting a new Trace - this will be the root span
22
+ id = ::Instana::Util.generate_id
23
+ @data[:t] = id # Trace ID
24
+ @data[:s] = id # Span ID
25
+ is_root = true
26
+ else
27
+ if parent_ctx.is_a?(::Instana::Span)
28
+ @parent = parent_ctx
29
+ parent_context = parent_ctx.context
30
+ elsif parent_ctx.is_a?(::Instana::SpanContext)
31
+ parent_context = parent_ctx
32
+ end
33
+
34
+ @data[:t] = parent_context.trace_id # Trace ID
35
+ @data[:s] = ::Instana::Util.generate_id # Span ID
36
+ @data[:p] = parent_context.span_id # Parent ID
37
+ @baggage = parent_ctx.baggage.dup
38
+ is_root = false
39
+ end
40
+
41
+ @data[:data] = {}
42
+
43
+ # Entity Source
44
+ @data[:f] = { :e => ::Instana.agent.report_pid,
45
+ :h => ::Instana.agent.agent_uuid }
46
+ # Start time
47
+ if start_time.is_a?(Time)
48
+ @data[:ts] = ::Instana::Util.time_to_ms(start_time)
49
+ else
50
+ @data[:ts] = start_time
51
+ end
52
+
53
+ if ::Instana.config[:collect_backtraces]
54
+ # For entry spans, add a backtrace fingerprint
55
+ add_stack(limit: 2) if ENTRY_SPANS.include?(name)
56
+
57
+ # Attach a backtrace to all exit spans
58
+ add_stack if EXIT_SPANS.include?(name)
59
+ end
60
+
61
+ # Check for custom tracing
62
+ if REGISTERED_SPANS.include?(name.to_sym)
63
+ @data[:n] = name.to_sym
64
+ else
65
+ configure_custom(name)
66
+ end
67
+ end
68
+
69
+ # Adds a backtrace to this span
70
+ #
71
+ # @param limit [Integer] Limit the backtrace to the top <limit> frames
72
+ #
73
+ def add_stack(limit: nil, stack: Kernel.caller)
74
+ frame_count = 0
75
+ @data[:stack] = []
76
+
77
+ stack.each do |i|
78
+ # If the stack has the full instana gem version in it's path
79
+ # then don't include that frame. Also don't exclude the Rack module.
80
+ if !i.match(/instana\/instrumentation\/rack.rb/).nil? ||
81
+ (i.match(::Instana::VERSION_FULL).nil? && i.match('lib/instana/').nil?)
82
+
83
+ break if limit && frame_count >= limit
84
+
85
+ x = i.split(':')
86
+
87
+ @data[:stack] << {
88
+ :c => x[0],
89
+ :n => x[1],
90
+ :m => x[2]
91
+ }
92
+ frame_count = frame_count + 1 if limit
93
+ end
94
+ end
95
+ end
96
+
97
+ # Log an error into the span
98
+ #
99
+ # @param e [Exception] The exception to be logged
100
+ #
101
+ def add_error(e)
102
+ @data[:error] = true
103
+
104
+ if @data.key?(:ec)
105
+ @data[:ec] = @data[:ec] + 1
106
+ else
107
+ @data[:ec] = 1
108
+ end
109
+
110
+ # If a valid exception has been passed in, log the information about it
111
+ # In case of just logging an error for things such as HTTP client 5xx
112
+ # responses, an exception/backtrace may not exist.
113
+ if e
114
+ if e.backtrace.is_a?(Array)
115
+ add_stack(stack: e.backtrace)
116
+ end
117
+
118
+ if HTTP_SPANS.include?(@data[:n])
119
+ set_tags(:http => { :error => "#{e.class}: #{e.message}" })
120
+ else
121
+ log(:error, Time.now, { :message => e.message, :parameters => e.class.to_s })
122
+ end
123
+ e.instance_variable_set(:@instana_logged, true)
124
+ end
125
+ self
126
+ end
127
+
128
+
129
+ # Configure this span to be a custom span per the
130
+ # SDK generic span type.
131
+ #
132
+ # Default to an intermediate kind span. Can be overridden by
133
+ # setting a span.kind tag.
134
+ #
135
+ # @param name [String] name of the span
136
+ # @param kvs [Hash] list of key values to be reported in the span
137
+ #
138
+ def configure_custom(name)
139
+ @data[:n] = :sdk
140
+ @data[:k] = 3
141
+ @data[:data] = { :sdk => { :name => name.to_sym, :type => :intermediate } }
142
+ @data[:data][:sdk][:custom] = { :tags => {}, :logs => {} }
143
+ self
144
+ end
145
+
146
+ # Closes out the span. This difference between this and
147
+ # the finish method tells us how the tracing is being
148
+ # performed (with OpenTracing or Instana default)
149
+ #
150
+ # @param end_time [Time] custom end time, if not now
151
+ # @return [Span]
152
+ #
153
+ def close(end_time = ::Instana::Util.now_in_ms)
154
+ if end_time.is_a?(Time)
155
+ end_time = ::Instana::Util.time_to_ms(end_time)
156
+ end
157
+
158
+ @data[:d] = end_time - @data[:ts]
159
+
160
+ # Add this span to the queue for reporting
161
+ ::Instana.processor.add_span(self)
162
+
163
+ self
164
+ end
165
+
166
+ #############################################################
167
+ # Accessors
168
+ #############################################################
169
+
170
+ # Retrieve the context of this span.
171
+ #
172
+ # @return [Instana::SpanContext]
173
+ #
174
+ def context
175
+ @context ||= ::Instana::SpanContext.new(@data[:t], @data[:s], 1, @baggage)
176
+ end
177
+
178
+ # Retrieve the ID for this span
179
+ #
180
+ # @return [Integer] the span ID
181
+ def id
182
+ @data[:s]
183
+ end
184
+
185
+ # Retrieve the Trace ID for this span
186
+ #
187
+ # @return [Integer] the Trace ID
188
+ def trace_id
189
+ @data[:t]
190
+ end
191
+
192
+ # Retrieve the parent ID of this span
193
+ #
194
+ # @return [Integer] parent span ID
195
+ def parent_id
196
+ @data[:p]
197
+ end
198
+
199
+ # Set the parent ID of this span
200
+ #
201
+ # @return [Integer] parent span ID
202
+ def parent_id=(id)
203
+ @data[:p] = id
204
+ end
205
+
206
+ # Get the name (operation) of this Span
207
+ #
208
+ # @return [String] or [Symbol] representing the span name
209
+ def name
210
+ if custom?
211
+ @data[:data][:sdk][:name]
212
+ else
213
+ @data[:n]
214
+ end
215
+ end
216
+
217
+ # Set the name (operation) for this Span
218
+ #
219
+ # @params name [String] or [Symbol]
220
+ #
221
+ def name=(n)
222
+ if custom?
223
+ @data[:data][:sdk][:name] = n
224
+ else
225
+ @data[:n] = n
226
+ end
227
+ end
228
+
229
+ # Get the duration value for this Span
230
+ #
231
+ # @return [Integer] the duration in milliseconds
232
+ def duration
233
+ @data[:d]
234
+ end
235
+
236
+ # Hash accessor to the internal @data hash
237
+ #
238
+ def [](key)
239
+ @data[key.to_sym]
240
+ end
241
+
242
+ # Hash setter to the internal @data hash
243
+ #
244
+ def []=(key, value)
245
+ @data[key.to_sym] = value
246
+ end
247
+
248
+ # Hash key query to the internal @data hash
249
+ #
250
+ def key?(k)
251
+ @data.key?(k.to_sym)
252
+ end
253
+
254
+ # Get the raw @data hash that summarizes this span
255
+ #
256
+ def raw
257
+ @data
258
+ end
259
+
260
+ # Indicates whether this span is a custom or registered Span
261
+ def custom?
262
+ @data[:n] == :sdk
263
+ end
264
+
265
+ def inspect
266
+ @data.inspect
267
+ end
268
+
269
+ #############################################################
270
+ # OpenTracing Compatibility Methods
271
+ #############################################################
272
+
273
+ # Set the name of the operation
274
+ # Spec: OpenTracing API
275
+ #
276
+ # @params name [String] or [Symbol]
277
+ #
278
+ def operation_name=(name)
279
+ @data[:n] = name
280
+ end
281
+
282
+ # Set a tag value on this span
283
+ # Spec: OpenTracing API
284
+ #
285
+ # @param key [String] the key of the tag
286
+ # @param value [String, Numeric, Boolean] the value of the tag. If it's not
287
+ # a String, Numeric, or Boolean it will be encoded with to_s
288
+ #
289
+ def set_tag(key, value)
290
+ if custom?
291
+ @data[:data][:sdk][:custom] ||= {}
292
+ @data[:data][:sdk][:custom][:tags] ||= {}
293
+ @data[:data][:sdk][:custom][:tags][key] = value
294
+
295
+ if key.to_sym == :'span.kind'
296
+ case value.to_sym
297
+ when :server, :consumer
298
+ @data[:data][:sdk][:type] = :entry
299
+ @data[:k] = 1
300
+ when :client, :producer
301
+ @data[:data][:sdk][:type] = :exit
302
+ @data[:k] = 2
303
+ else
304
+ @data[:data][:sdk][:type] = :intermediate
305
+ @data[:k] = 3
306
+ end
307
+ end
308
+ else
309
+ if !@data[:data].key?(key)
310
+ @data[:data][key] = value
311
+ elsif value.is_a?(Hash) && self[:data][key].is_a?(Hash)
312
+ @data[:data][key].merge!(value)
313
+ else
314
+ @data[:data][key] = value
315
+ end
316
+ end
317
+ self
318
+ end
319
+
320
+ # Helper method to add multiple tags to this span
321
+ #
322
+ # @params tags [Hash]
323
+ # @return [Span]
324
+ #
325
+ def set_tags(tags)
326
+ return unless tags.is_a?(Hash)
327
+ tags.each do |k,v|
328
+ set_tag(k, v)
329
+ end
330
+ self
331
+ end
332
+
333
+ # Set a baggage item on the span
334
+ # Spec: OpenTracing API
335
+ #
336
+ # @param key [String] the key of the baggage item
337
+ # @param value [String] the value of the baggage item
338
+ def set_baggage_item(key, value)
339
+ @baggage ||= {}
340
+ @baggage[key] = value
341
+
342
+ # Init/Update the SpanContext item
343
+ if @context
344
+ @context.baggage = @baggage
345
+ else
346
+ @context ||= ::Instana::SpanContext.new(@data[:t], @data[:s], 1, @baggage)
347
+ end
348
+ self
349
+ end
350
+
351
+ # Get a baggage item
352
+ # Spec: OpenTracing API
353
+ #
354
+ # @param key [String] the key of the baggage item
355
+ # @return Value of the baggage item
356
+ #
357
+ def get_baggage_item(key)
358
+ @baggage[key]
359
+ end
360
+
361
+ # Retrieve the hash of tags for this span
362
+ #
363
+ def tags(key = nil)
364
+ if custom?
365
+ tags = @data[:data][:sdk][:custom][:tags]
366
+ else
367
+ tags = @data[:data][key]
368
+ end
369
+ key ? tags[key] : tags
370
+ end
371
+
372
+ # Add a log entry to this span
373
+ # Spec: OpenTracing API
374
+ #
375
+ # @param event [String] event name for the log
376
+ # @param timestamp [Time] time of the log
377
+ # @param fields [Hash] Additional information to log
378
+ #
379
+ def log(event = nil, timestamp = Time.now, **fields)
380
+ ts = ::Instana::Util.time_to_ms(timestamp).to_s
381
+ if custom?
382
+ @data[:data][:sdk][:custom][:logs][ts] = fields
383
+ @data[:data][:sdk][:custom][:logs][ts][:event] = event
384
+ else
385
+ set_tags(:log => fields)
386
+ end
387
+ rescue StandardError => e
388
+ Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
389
+ end
390
+
391
+ # Finish the {Span}
392
+ # Spec: OpenTracing API
393
+ #
394
+ # @param end_time [Time] custom end time, if not now
395
+ #
396
+ def finish(end_time = ::Instana::Util.now_in_ms)
397
+ close(end_time)
398
+ self
399
+ end
400
+ end
401
+ end