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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +395 -364
- data/CLA.md +1 -1
- data/LICENSE.md +7 -17
- data/README.md +1 -1
- data/ext/extconf.rb +42 -54
- data/ext/libskylight.yml +9 -6
- data/lib/skylight.rb +20 -30
- data/lib/skylight/api.rb +22 -18
- data/lib/skylight/cli.rb +47 -46
- data/lib/skylight/cli/doctor.rb +50 -50
- data/lib/skylight/cli/helpers.rb +19 -19
- data/lib/skylight/cli/merger.rb +141 -139
- data/lib/skylight/config.rb +265 -300
- data/lib/skylight/deprecation.rb +4 -4
- data/lib/skylight/errors.rb +3 -4
- data/lib/skylight/extensions.rb +17 -29
- data/lib/skylight/extensions/source_location.rb +128 -128
- data/lib/skylight/formatters/http.rb +1 -3
- data/lib/skylight/gc.rb +30 -40
- data/lib/skylight/helpers.rb +43 -41
- data/lib/skylight/instrumenter.rb +25 -18
- data/lib/skylight/middleware.rb +31 -35
- data/lib/skylight/native.rb +8 -10
- data/lib/skylight/native_ext_fetcher.rb +10 -12
- data/lib/skylight/normalizers.rb +43 -39
- data/lib/skylight/normalizers/action_controller/process_action.rb +24 -25
- data/lib/skylight/normalizers/action_controller/send_file.rb +7 -6
- data/lib/skylight/normalizers/action_dispatch/route_set.rb +7 -7
- data/lib/skylight/normalizers/active_job/perform.rb +48 -44
- data/lib/skylight/normalizers/active_model_serializers/render.rb +7 -3
- data/lib/skylight/normalizers/active_storage.rb +11 -13
- data/lib/skylight/normalizers/active_support/cache.rb +1 -12
- data/lib/skylight/normalizers/coach/handler_finish.rb +1 -3
- data/lib/skylight/normalizers/default.rb +1 -9
- data/lib/skylight/normalizers/faraday/request.rb +1 -3
- data/lib/skylight/normalizers/grape/endpoint.rb +13 -19
- data/lib/skylight/normalizers/grape/endpoint_run.rb +16 -18
- data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +1 -3
- data/lib/skylight/normalizers/graphql/base.rb +23 -28
- data/lib/skylight/normalizers/render.rb +19 -21
- data/lib/skylight/normalizers/shrine.rb +15 -17
- data/lib/skylight/normalizers/sql.rb +4 -4
- data/lib/skylight/probes.rb +38 -46
- data/lib/skylight/probes/action_controller.rb +32 -28
- data/lib/skylight/probes/action_dispatch/request_id.rb +9 -5
- data/lib/skylight/probes/action_dispatch/routing/route_set.rb +7 -5
- data/lib/skylight/probes/action_view.rb +9 -10
- data/lib/skylight/probes/active_job_enqueue.rb +3 -9
- data/lib/skylight/probes/active_model_serializers.rb +8 -8
- data/lib/skylight/probes/delayed_job.rb +37 -42
- data/lib/skylight/probes/elasticsearch.rb +3 -5
- data/lib/skylight/probes/excon.rb +1 -1
- data/lib/skylight/probes/excon/middleware.rb +22 -23
- data/lib/skylight/probes/graphql.rb +2 -7
- data/lib/skylight/probes/middleware.rb +14 -5
- data/lib/skylight/probes/mongo.rb +83 -91
- data/lib/skylight/probes/net_http.rb +1 -1
- data/lib/skylight/probes/redis.rb +5 -17
- data/lib/skylight/probes/sequel.rb +7 -11
- data/lib/skylight/probes/sinatra.rb +8 -5
- data/lib/skylight/probes/tilt.rb +2 -4
- data/lib/skylight/railtie.rb +121 -135
- data/lib/skylight/sidekiq.rb +4 -5
- data/lib/skylight/subscriber.rb +31 -33
- data/lib/skylight/test.rb +89 -84
- data/lib/skylight/trace.rb +121 -115
- data/lib/skylight/user_config.rb +14 -17
- data/lib/skylight/util/clock.rb +1 -0
- data/lib/skylight/util/component.rb +18 -21
- data/lib/skylight/util/deploy.rb +11 -13
- data/lib/skylight/util/http.rb +104 -105
- data/lib/skylight/util/logging.rb +4 -6
- data/lib/skylight/util/lru_cache.rb +2 -6
- data/lib/skylight/util/platform.rb +2 -6
- data/lib/skylight/util/ssl.rb +1 -25
- data/lib/skylight/version.rb +1 -1
- data/lib/skylight/vm/gc.rb +1 -9
- 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 =
|
8
|
-
|
9
|
-
|
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(
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
const_set(
|
22
|
+
:Instrumenter,
|
23
|
+
Class.new(OriginalInstrumenter) do
|
24
|
+
def self.name
|
25
|
+
"Mocked Instrumenter"
|
26
|
+
end
|
24
27
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
+
def self.native_new(*)
|
29
|
+
allocate
|
30
|
+
end
|
28
31
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
+
def native_start
|
33
|
+
true
|
34
|
+
end
|
32
35
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
+
def native_submit_trace(trace)
|
37
|
+
config[:mock_submission].call(trace)
|
38
|
+
end
|
36
39
|
|
37
|
-
|
38
|
-
|
40
|
+
def native_stop; end
|
41
|
+
end
|
42
|
+
)
|
39
43
|
|
40
44
|
const_set :OriginalTrace, Trace
|
41
45
|
remove_const :Trace
|
42
|
-
const_set(
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
58
|
+
attr_reader :endpoint, :starting_endpoint, :meta
|
53
59
|
|
54
|
-
|
55
|
-
|
56
|
-
|
60
|
+
def mock_spans
|
61
|
+
@mock_spans ||= []
|
62
|
+
end
|
57
63
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
-
|
67
|
-
|
68
|
-
|
72
|
+
def native_get_uuid
|
73
|
+
@uuid
|
74
|
+
end
|
69
75
|
|
70
|
-
|
71
|
-
|
72
|
-
|
76
|
+
def uuid=(value)
|
77
|
+
@uuid = value
|
78
|
+
end
|
73
79
|
|
74
|
-
|
75
|
-
|
76
|
-
|
80
|
+
def native_get_started_at
|
81
|
+
@start
|
82
|
+
end
|
77
83
|
|
78
|
-
|
79
|
-
|
80
|
-
|
84
|
+
def native_set_endpoint(endpoint)
|
85
|
+
@endpoint = endpoint
|
86
|
+
end
|
81
87
|
|
82
|
-
|
83
|
-
|
84
|
-
|
88
|
+
def native_set_component(component)
|
89
|
+
@component = component
|
90
|
+
end
|
85
91
|
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
97
|
-
|
98
|
-
|
96
|
+
# Return integer like the native method does
|
97
|
+
mock_spans.index(span)
|
98
|
+
end
|
99
99
|
|
100
|
-
|
101
|
-
|
102
|
-
|
100
|
+
def native_span_set_title(span, title)
|
101
|
+
mock_spans[span][:title] = title
|
102
|
+
end
|
103
103
|
|
104
|
-
|
105
|
-
|
106
|
-
|
104
|
+
def native_span_set_description(span, desc)
|
105
|
+
mock_spans[span][:desc] = desc
|
106
|
+
end
|
107
107
|
|
108
|
-
|
108
|
+
def native_span_set_meta(span, meta)
|
109
|
+
mock_spans[span][:meta] = meta
|
110
|
+
end
|
109
111
|
|
110
|
-
|
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
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
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
|
-
|
122
|
-
|
125
|
+
def native_use_pruning
|
126
|
+
@using_native_pruning = true
|
127
|
+
end
|
123
128
|
end
|
124
|
-
|
129
|
+
)
|
125
130
|
end
|
126
131
|
end
|
127
132
|
|
data/lib/skylight/trace.rb
CHANGED
@@ -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
|
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(
|
180
|
-
|
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
|
-
|
218
|
-
|
219
|
-
|
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
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
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
|
-
|
229
|
-
|
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
|
-
|
240
|
-
t { "started span: #{sp} - #{cat}, #{title}" }
|
235
|
+
mute_children = meta&.delete(:mute_children)
|
241
236
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
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
|
-
|
248
|
-
|
243
|
+
@spans << sp
|
244
|
+
t { "started span: #{sp} - #{cat}, #{title}" }
|
249
245
|
|
250
|
-
|
251
|
-
|
246
|
+
if mute_children
|
247
|
+
t { "muting child instrumentation for span=#{sp}" }
|
248
|
+
mute_child_instrumentation(sp)
|
252
249
|
end
|
253
250
|
|
254
|
-
|
255
|
-
|
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
|
-
|
262
|
-
|
254
|
+
def mute_child_instrumentation(span)
|
255
|
+
@child_instrumentation_muted_by = span
|
256
|
+
end
|
263
257
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
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
|
-
|
265
|
+
def stop(span, time)
|
266
|
+
t { "stopping span: #{span}" }
|
272
267
|
|
273
|
-
|
274
|
-
|
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
|
-
|
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
|
-
|
282
|
-
|
283
|
-
|
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
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
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
|
-
|
309
|
+
message << "\nThis request will not be tracked. Please contact support@skylight.io for more information."
|
304
310
|
|
305
|
-
|
311
|
+
error message
|
306
312
|
|
307
|
-
|
313
|
+
t { "expected=#{expected}, actual=#{span}" }
|
308
314
|
|
309
|
-
|
310
|
-
|
315
|
+
broken!
|
316
|
+
end
|
311
317
|
|
312
|
-
|
313
|
-
|
318
|
+
def gc_time
|
319
|
+
return 0 unless @gc
|
314
320
|
|
315
|
-
|
316
|
-
|
317
|
-
|
321
|
+
@gc.update
|
322
|
+
@gc.time
|
323
|
+
end
|
318
324
|
|
319
|
-
|
320
|
-
|
321
|
-
|
325
|
+
def use_pruning?
|
326
|
+
config.get(:prune_large_traces)
|
327
|
+
end
|
322
328
|
|
323
|
-
|
324
|
-
|
325
|
-
|
329
|
+
def resolve_component(component)
|
330
|
+
config.components[component].to_encoded_s
|
331
|
+
end
|
326
332
|
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
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
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
341
|
+
def preprocess_meta(meta)
|
342
|
+
validate_meta(meta)
|
343
|
+
instrumenter.extensions.trace_preprocess_meta(meta)
|
344
|
+
end
|
339
345
|
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
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
|
-
|
351
|
-
|
352
|
-
|
356
|
+
def allowed_meta_keys
|
357
|
+
META_KEYS | instrumenter.extensions.allowed_meta_keys
|
358
|
+
end
|
353
359
|
|
354
|
-
|
355
|
-
|
360
|
+
def maybe_warn(context, msg)
|
361
|
+
return if warnings_silenced?(context)
|
356
362
|
|
357
|
-
|
363
|
+
instrumenter.silence_warnings(context)
|
358
364
|
|
359
|
-
|
360
|
-
|
365
|
+
warn(msg)
|
366
|
+
end
|
361
367
|
|
362
|
-
|
363
|
-
|
364
|
-
|
368
|
+
def warnings_silenced?(context)
|
369
|
+
instrumenter.warnings_silenced?(context)
|
370
|
+
end
|
365
371
|
end
|
366
372
|
end
|