skylight 5.0.1 → 5.1.1

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 (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