skylight 5.0.1 → 5.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +395 -364
  3. data/CLA.md +1 -1
  4. data/LICENSE.md +7 -17
  5. data/README.md +1 -1
  6. data/ext/extconf.rb +42 -54
  7. data/ext/libskylight.yml +9 -6
  8. data/lib/skylight.rb +20 -30
  9. data/lib/skylight/api.rb +22 -18
  10. data/lib/skylight/cli.rb +47 -46
  11. data/lib/skylight/cli/doctor.rb +50 -50
  12. data/lib/skylight/cli/helpers.rb +19 -19
  13. data/lib/skylight/cli/merger.rb +141 -139
  14. data/lib/skylight/config.rb +265 -300
  15. data/lib/skylight/deprecation.rb +4 -4
  16. data/lib/skylight/errors.rb +3 -4
  17. data/lib/skylight/extensions.rb +17 -29
  18. data/lib/skylight/extensions/source_location.rb +128 -128
  19. data/lib/skylight/formatters/http.rb +1 -3
  20. data/lib/skylight/gc.rb +30 -40
  21. data/lib/skylight/helpers.rb +43 -41
  22. data/lib/skylight/instrumenter.rb +25 -18
  23. data/lib/skylight/middleware.rb +31 -35
  24. data/lib/skylight/native.rb +8 -10
  25. data/lib/skylight/native_ext_fetcher.rb +10 -12
  26. data/lib/skylight/normalizers.rb +43 -39
  27. data/lib/skylight/normalizers/action_controller/process_action.rb +24 -25
  28. data/lib/skylight/normalizers/action_controller/send_file.rb +7 -6
  29. data/lib/skylight/normalizers/action_dispatch/route_set.rb +7 -7
  30. data/lib/skylight/normalizers/active_job/perform.rb +48 -44
  31. data/lib/skylight/normalizers/active_model_serializers/render.rb +7 -3
  32. data/lib/skylight/normalizers/active_storage.rb +11 -13
  33. data/lib/skylight/normalizers/active_support/cache.rb +1 -12
  34. data/lib/skylight/normalizers/coach/handler_finish.rb +1 -3
  35. data/lib/skylight/normalizers/default.rb +1 -9
  36. data/lib/skylight/normalizers/faraday/request.rb +1 -3
  37. data/lib/skylight/normalizers/grape/endpoint.rb +13 -19
  38. data/lib/skylight/normalizers/grape/endpoint_run.rb +16 -18
  39. data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +1 -3
  40. data/lib/skylight/normalizers/graphql/base.rb +23 -28
  41. data/lib/skylight/normalizers/render.rb +19 -21
  42. data/lib/skylight/normalizers/shrine.rb +15 -17
  43. data/lib/skylight/normalizers/sql.rb +4 -4
  44. data/lib/skylight/probes.rb +38 -46
  45. data/lib/skylight/probes/action_controller.rb +32 -28
  46. data/lib/skylight/probes/action_dispatch/request_id.rb +9 -5
  47. data/lib/skylight/probes/action_dispatch/routing/route_set.rb +7 -5
  48. data/lib/skylight/probes/action_view.rb +9 -10
  49. data/lib/skylight/probes/active_job_enqueue.rb +3 -9
  50. data/lib/skylight/probes/active_model_serializers.rb +8 -8
  51. data/lib/skylight/probes/delayed_job.rb +37 -42
  52. data/lib/skylight/probes/elasticsearch.rb +3 -5
  53. data/lib/skylight/probes/excon.rb +1 -1
  54. data/lib/skylight/probes/excon/middleware.rb +22 -23
  55. data/lib/skylight/probes/graphql.rb +2 -7
  56. data/lib/skylight/probes/middleware.rb +14 -5
  57. data/lib/skylight/probes/mongo.rb +83 -91
  58. data/lib/skylight/probes/net_http.rb +1 -1
  59. data/lib/skylight/probes/redis.rb +5 -17
  60. data/lib/skylight/probes/sequel.rb +7 -11
  61. data/lib/skylight/probes/sinatra.rb +8 -5
  62. data/lib/skylight/probes/tilt.rb +2 -4
  63. data/lib/skylight/railtie.rb +121 -135
  64. data/lib/skylight/sidekiq.rb +4 -5
  65. data/lib/skylight/subscriber.rb +31 -33
  66. data/lib/skylight/test.rb +89 -84
  67. data/lib/skylight/trace.rb +121 -115
  68. data/lib/skylight/user_config.rb +14 -17
  69. data/lib/skylight/util/clock.rb +1 -0
  70. data/lib/skylight/util/component.rb +18 -21
  71. data/lib/skylight/util/deploy.rb +11 -13
  72. data/lib/skylight/util/http.rb +104 -105
  73. data/lib/skylight/util/logging.rb +4 -6
  74. data/lib/skylight/util/lru_cache.rb +2 -6
  75. data/lib/skylight/util/platform.rb +2 -6
  76. data/lib/skylight/util/ssl.rb +1 -25
  77. data/lib/skylight/version.rb +1 -1
  78. data/lib/skylight/vm/gc.rb +1 -9
  79. metadata +6 -6
data/lib/skylight/test.rb CHANGED
@@ -4,11 +4,12 @@ module Skylight
4
4
  def mock!(config_opts = {}, &callback)
5
5
  config_opts[:mock_submission] ||= callback || proc {}
6
6
 
7
- config_class = Class.new(Config) do
8
- def validate_with_server
9
- true
7
+ config_class =
8
+ Class.new(Config) do
9
+ def validate_with_server
10
+ true
11
+ end
10
12
  end
11
- end
12
13
 
13
14
  config = config_class.load(config_opts)
14
15
  config[:authentication] ||= "zomg"
@@ -17,111 +18,115 @@ module Skylight
17
18
  unless const_defined?(:OriginalInstrumenter)
18
19
  const_set :OriginalInstrumenter, Instrumenter
19
20
  remove_const :Instrumenter
20
- const_set(:Instrumenter, Class.new(OriginalInstrumenter) do
21
- def self.name
22
- "Mocked Instrumenter"
23
- end
21
+ const_set(
22
+ :Instrumenter,
23
+ Class.new(OriginalInstrumenter) do
24
+ def self.name
25
+ "Mocked Instrumenter"
26
+ end
24
27
 
25
- def self.native_new(*)
26
- allocate
27
- end
28
+ def self.native_new(*)
29
+ allocate
30
+ end
28
31
 
29
- def native_start
30
- true
31
- end
32
+ def native_start
33
+ true
34
+ end
32
35
 
33
- def native_submit_trace(trace)
34
- config[:mock_submission].call(trace)
35
- end
36
+ def native_submit_trace(trace)
37
+ config[:mock_submission].call(trace)
38
+ end
36
39
 
37
- def native_stop; end
38
- end)
40
+ def native_stop; end
41
+ end
42
+ )
39
43
 
40
44
  const_set :OriginalTrace, Trace
41
45
  remove_const :Trace
42
- const_set(:Trace, Class.new(OriginalTrace) do
43
- def self.native_new(start, _uuid, endpoint, meta)
44
- inst = allocate
45
- inst.instance_variable_set(:@start, start)
46
- inst.instance_variable_set(:@endpoint, endpoint)
47
- inst.instance_variable_set(:@starting_endpoint, endpoint)
48
- inst.instance_variable_set(:@meta, meta)
49
- inst
50
- end
46
+ const_set(
47
+ :Trace,
48
+ Class.new(OriginalTrace) do
49
+ def self.native_new(start, _uuid, endpoint, meta)
50
+ inst = allocate
51
+ inst.instance_variable_set(:@start, start)
52
+ inst.instance_variable_set(:@endpoint, endpoint)
53
+ inst.instance_variable_set(:@starting_endpoint, endpoint)
54
+ inst.instance_variable_set(:@meta, meta)
55
+ inst
56
+ end
51
57
 
52
- attr_reader :endpoint, :starting_endpoint, :meta
58
+ attr_reader :endpoint, :starting_endpoint, :meta
53
59
 
54
- def mock_spans
55
- @mock_spans ||= []
56
- end
60
+ def mock_spans
61
+ @mock_spans ||= []
62
+ end
57
63
 
58
- def filter_spans
59
- if block_given?
60
- mock_spans.select { |span| yield span }
61
- else
62
- mock_spans.reject { |span| span[:cat] == "noise.gc" }
64
+ def filter_spans
65
+ if block_given?
66
+ mock_spans.select { |span| yield span }
67
+ else
68
+ mock_spans.reject { |span| span[:cat] == "noise.gc" }
69
+ end
63
70
  end
64
- end
65
71
 
66
- def native_get_uuid
67
- @uuid
68
- end
72
+ def native_get_uuid
73
+ @uuid
74
+ end
69
75
 
70
- def uuid=(value)
71
- @uuid = value
72
- end
76
+ def uuid=(value)
77
+ @uuid = value
78
+ end
73
79
 
74
- def native_get_started_at
75
- @start
76
- end
80
+ def native_get_started_at
81
+ @start
82
+ end
77
83
 
78
- def native_set_endpoint(endpoint)
79
- @endpoint = endpoint
80
- end
84
+ def native_set_endpoint(endpoint)
85
+ @endpoint = endpoint
86
+ end
81
87
 
82
- def native_set_component(component)
83
- @component = component
84
- end
88
+ def native_set_component(component)
89
+ @component = component
90
+ end
85
91
 
86
- def native_start_span(time, cat)
87
- span = {
88
- start: time,
89
- cat: cat
90
- }
91
- mock_spans << span
92
- # Return integer like the native method does
93
- mock_spans.index(span)
94
- end
92
+ def native_start_span(time, cat)
93
+ span = { start: time, cat: cat }
94
+ mock_spans << span
95
95
 
96
- def native_span_set_title(span, title)
97
- mock_spans[span][:title] = title
98
- end
96
+ # Return integer like the native method does
97
+ mock_spans.index(span)
98
+ end
99
99
 
100
- def native_span_set_description(span, desc)
101
- mock_spans[span][:desc] = desc
102
- end
100
+ def native_span_set_title(span, title)
101
+ mock_spans[span][:title] = title
102
+ end
103
103
 
104
- def native_span_set_meta(span, meta)
105
- mock_spans[span][:meta] = meta
106
- end
104
+ def native_span_set_description(span, desc)
105
+ mock_spans[span][:desc] = desc
106
+ end
107
107
 
108
- def native_span_started(span); end
108
+ def native_span_set_meta(span, meta)
109
+ mock_spans[span][:meta] = meta
110
+ end
109
111
 
110
- def native_span_set_exception(span, exception_object, exception)
111
- mock_spans[span][:exception_object] = exception_object
112
- mock_spans[span][:exception] = exception
113
- end
112
+ def native_span_started(span); end
114
113
 
115
- def native_stop_span(span, time)
116
- span = mock_spans[span]
117
- span[:duration] = time - span[:start]
118
- nil
119
- end
114
+ def native_span_set_exception(span, exception_object, exception)
115
+ mock_spans[span][:exception_object] = exception_object
116
+ mock_spans[span][:exception] = exception
117
+ end
118
+
119
+ def native_stop_span(span, time)
120
+ span = mock_spans[span]
121
+ span[:duration] = time - span[:start]
122
+ nil
123
+ end
120
124
 
121
- def native_use_pruning
122
- @using_native_pruning = true
125
+ def native_use_pruning
126
+ @using_native_pruning = true
127
+ end
123
128
  end
124
- end)
129
+ )
125
130
  end
126
131
  end
127
132
 
@@ -123,14 +123,14 @@ module Skylight
123
123
  t { "instrument: #{cat}, #{title}" }
124
124
 
125
125
  title.freeze if title.is_a?(String)
126
- desc.freeze if desc.is_a?(String)
126
+ desc.freeze if desc.is_a?(String)
127
127
 
128
128
  now = Skylight::Util::Clock.nanos
129
129
 
130
130
  preprocess_meta(meta) if meta
131
131
 
132
132
  start(now - gc_time, cat, title, desc, meta)
133
- rescue => e
133
+ rescue StandardError => e
134
134
  maybe_broken(e)
135
135
  nil
136
136
  end
@@ -151,7 +151,7 @@ module Skylight
151
151
  end
152
152
 
153
153
  stop(span, Skylight::Util::Clock.nanos - gc_time)
154
- rescue => e
154
+ rescue StandardError => e
155
155
  error "failed to close span; msg=%s; endpoint=%s", e.message, endpoint
156
156
  log_trace "Original Backtrace:\n#{e.backtrace.join("\n")}"
157
157
  broken!
@@ -176,8 +176,12 @@ module Skylight
176
176
 
177
177
  def traced
178
178
  if too_many_spans?
179
- error("[E%04d] The request exceeded the maximum number of spans allowed. It will still " \
180
- "be tracked but with reduced information. endpoint=%s", Skylight::MaximumTraceSpansError.code, endpoint)
179
+ error(
180
+ "[E%04d] The request exceeded the maximum number of spans allowed. It will still " \
181
+ "be tracked but with reduced information. endpoint=%s",
182
+ Skylight::MaximumTraceSpansError.code,
183
+ endpoint
184
+ )
181
185
  end
182
186
 
183
187
  gc = gc_time
@@ -214,153 +218,155 @@ module Skylight
214
218
 
215
219
  private
216
220
 
217
- def track_gc(time, now)
218
- # This attempts to log another span which will fail if we have too many
219
- return if too_many_spans?
221
+ def track_gc(time, now)
222
+ # This attempts to log another span which will fail if we have too many
223
+ return if too_many_spans?
220
224
 
221
- if time > 0
222
- t { fmt "tracking GC time; duration=%d", time }
223
- meta = { source_location: SYNTHETIC }
224
- stop(start(now - time, GC_CAT, nil, nil, meta), now)
225
- end
225
+ if time > 0
226
+ t { fmt "tracking GC time; duration=%d", time }
227
+ meta = { source_location: SYNTHETIC }
228
+ stop(start(now - time, GC_CAT, nil, nil, meta), now)
226
229
  end
230
+ end
227
231
 
228
- def start(time, cat, title, desc, meta, opts = {})
229
- time = self.class.normalize_time(time) unless opts[:normalize] == false
230
-
231
- mute_children = meta&.delete(:mute_children)
232
-
233
- sp = native_start_span(time, cat.to_s)
234
- native_span_set_title(sp, title.to_s) if title
235
- native_span_set_description(sp, desc.to_s) if desc
236
- native_span_set_meta(sp, meta) if meta
237
- native_span_started(sp)
232
+ def start(time, cat, title, desc, meta, opts = {})
233
+ time = self.class.normalize_time(time) unless opts[:normalize] == false
238
234
 
239
- @spans << sp
240
- t { "started span: #{sp} - #{cat}, #{title}" }
235
+ mute_children = meta&.delete(:mute_children)
241
236
 
242
- if mute_children
243
- t { "muting child instrumentation for span=#{sp}" }
244
- mute_child_instrumentation(sp)
245
- end
237
+ sp = native_start_span(time, cat.to_s)
238
+ native_span_set_title(sp, title.to_s) if title
239
+ native_span_set_description(sp, desc.to_s) if desc
240
+ native_span_set_meta(sp, meta) if meta
241
+ native_span_started(sp)
246
242
 
247
- sp
248
- end
243
+ @spans << sp
244
+ t { "started span: #{sp} - #{cat}, #{title}" }
249
245
 
250
- def mute_child_instrumentation(span)
251
- @child_instrumentation_muted_by = span
246
+ if mute_children
247
+ t { "muting child instrumentation for span=#{sp}" }
248
+ mute_child_instrumentation(sp)
252
249
  end
253
250
 
254
- # Middleware spans that were interrupted by a throw/catch should be cached here.
255
- # keys: span ids
256
- # values: nsec timestamp at which the span was cached here.
257
- def deferred_spans
258
- @deferred_spans ||= {}
259
- end
251
+ sp
252
+ end
260
253
 
261
- def stop(span, time)
262
- t { "stopping span: #{span}" }
254
+ def mute_child_instrumentation(span)
255
+ @child_instrumentation_muted_by = span
256
+ end
263
257
 
264
- # If `stop` is called for a span that is not the last item in the stack,
265
- # check to see if the last item has been marked as deferred. If so, close
266
- # that span first, then try to close the original.
267
- while deferred_spans[expected = @spans.pop]
268
- normalized_stop(expected, deferred_spans.delete(expected))
269
- end
258
+ # Middleware spans that were interrupted by a throw/catch should be cached here.
259
+ # keys: span ids
260
+ # values: nsec timestamp at which the span was cached here.
261
+ def deferred_spans
262
+ @deferred_spans ||= {}
263
+ end
270
264
 
271
- handle_unexpected_stop(expected, span) unless span == expected
265
+ def stop(span, time)
266
+ t { "stopping span: #{span}" }
272
267
 
273
- normalized_stop(span, time)
274
- nil
268
+ # If `stop` is called for a span that is not the last item in the stack,
269
+ # check to see if the last item has been marked as deferred. If so, close
270
+ # that span first, then try to close the original.
271
+ while deferred_spans[expected = @spans.pop]
272
+ normalized_stop(expected, deferred_spans.delete(expected))
275
273
  end
276
274
 
277
- def normalized_stop(span, time)
278
- time = self.class.normalize_time(time)
279
- native_stop_span(span, time)
275
+ handle_unexpected_stop(expected, span) unless span == expected
280
276
 
281
- if @child_instrumentation_muted_by == span
282
- @child_instrumentation_muted_by = nil # restart instrumenting
283
- end
277
+ normalized_stop(span, time)
278
+ nil
279
+ end
280
+
281
+ def normalized_stop(span, time)
282
+ time = self.class.normalize_time(time)
283
+ native_stop_span(span, time)
284
+
285
+ if @child_instrumentation_muted_by == span
286
+ @child_instrumentation_muted_by = nil # restart instrumenting
284
287
  end
288
+ end
285
289
 
286
- # Originally extracted from `stop`.
287
- # If we attempt to close spans out of order, and it appears to be a middleware issue,
288
- # disable the middleware probe and mark trace as broken.
289
- def handle_unexpected_stop(expected, span)
290
- message = "[E0001] Spans were closed out of order. Expected to see '#{native_span_get_title(expected)}', " \
291
- "but got '#{native_span_get_title(span)}' instead."
292
-
293
- if native_span_get_category(span) == "rack.middleware" && Skylight::Probes.installed.key?(:middleware)
294
- if Skylight::Probes::Middleware::Probe.disabled?
295
- message << "\nWe disabled the Middleware probe but unfortunately, this didn't solve the issue."
296
- else
297
- Skylight::Probes::Middleware::Probe.disable!
298
- message << "\n#{native_span_get_title(span)} may be a Middleware that doesn't fully conform " \
299
- "to the Rack SPEC. We've disabled the Middleware probe to see if that resolves the issue."
300
- end
290
+ # Originally extracted from `stop`.
291
+ # If we attempt to close spans out of order, and it appears to be a middleware issue,
292
+ # disable the middleware probe and mark trace as broken.
293
+ def handle_unexpected_stop(expected, span)
294
+ message =
295
+ "[E0001] Spans were closed out of order. Expected to see '#{native_span_get_title(expected)}', " \
296
+ "but got '#{native_span_get_title(span)}' instead."
297
+
298
+ if native_span_get_category(span) == "rack.middleware" && Skylight::Probes.installed.key?(:middleware)
299
+ if Skylight::Probes::Middleware::Probe.disabled?
300
+ message << "\nWe disabled the Middleware probe but unfortunately, this didn't solve the issue."
301
+ else
302
+ Skylight::Probes::Middleware::Probe.disable!
303
+ message <<
304
+ "\n#{native_span_get_title(span)} may be a Middleware that doesn't fully conform " \
305
+ "to the Rack SPEC. We've disabled the Middleware probe to see if that resolves the issue."
301
306
  end
307
+ end
302
308
 
303
- message << "\nThis request will not be tracked. Please contact support@skylight.io for more information."
309
+ message << "\nThis request will not be tracked. Please contact support@skylight.io for more information."
304
310
 
305
- error message
311
+ error message
306
312
 
307
- t { "expected=#{expected}, actual=#{span}" }
313
+ t { "expected=#{expected}, actual=#{span}" }
308
314
 
309
- broken!
310
- end
315
+ broken!
316
+ end
311
317
 
312
- def gc_time
313
- return 0 unless @gc
318
+ def gc_time
319
+ return 0 unless @gc
314
320
 
315
- @gc.update
316
- @gc.time
317
- end
321
+ @gc.update
322
+ @gc.time
323
+ end
318
324
 
319
- def use_pruning?
320
- config.get(:prune_large_traces)
321
- end
325
+ def use_pruning?
326
+ config.get(:prune_large_traces)
327
+ end
322
328
 
323
- def resolve_component(component)
324
- config.components[component].to_encoded_s
325
- end
329
+ def resolve_component(component)
330
+ config.components[component].to_encoded_s
331
+ end
326
332
 
327
- def component=(component)
328
- resolve_component(component).tap do |c|
329
- # Would it be better for the component getter to get from native?
330
- @component = c
331
- native_set_component(c)
332
- end
333
+ def component=(component)
334
+ resolve_component(component).tap do |c|
335
+ # Would it be better for the component getter to get from native?
336
+ @component = c
337
+ native_set_component(c)
333
338
  end
339
+ end
334
340
 
335
- def preprocess_meta(meta)
336
- validate_meta(meta)
337
- instrumenter.extensions.trace_preprocess_meta(meta)
338
- end
341
+ def preprocess_meta(meta)
342
+ validate_meta(meta)
343
+ instrumenter.extensions.trace_preprocess_meta(meta)
344
+ end
339
345
 
340
- def validate_meta(meta)
341
- unknown_keys = meta.keys - allowed_meta_keys
342
- if unknown_keys.any?
343
- unknown_keys.each do |key|
344
- maybe_warn("unknown_meta:#{key}", "Unknown meta key will be ignored; key=#{key.inspect}")
345
- meta.delete(key)
346
- end
346
+ def validate_meta(meta)
347
+ unknown_keys = meta.keys - allowed_meta_keys
348
+ if unknown_keys.any?
349
+ unknown_keys.each do |key|
350
+ maybe_warn("unknown_meta:#{key}", "Unknown meta key will be ignored; key=#{key.inspect}")
351
+ meta.delete(key)
347
352
  end
348
353
  end
354
+ end
349
355
 
350
- def allowed_meta_keys
351
- META_KEYS | instrumenter.extensions.allowed_meta_keys
352
- end
356
+ def allowed_meta_keys
357
+ META_KEYS | instrumenter.extensions.allowed_meta_keys
358
+ end
353
359
 
354
- def maybe_warn(context, msg)
355
- return if warnings_silenced?(context)
360
+ def maybe_warn(context, msg)
361
+ return if warnings_silenced?(context)
356
362
 
357
- instrumenter.silence_warnings(context)
363
+ instrumenter.silence_warnings(context)
358
364
 
359
- warn(msg)
360
- end
365
+ warn(msg)
366
+ end
361
367
 
362
- def warnings_silenced?(context)
363
- instrumenter.warnings_silenced?(context)
364
- end
368
+ def warnings_silenced?(context)
369
+ instrumenter.warnings_silenced?(context)
370
+ end
365
371
  end
366
372
  end