skylight 4.3.2 → 5.0.0.beta
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 +14 -5
- data/CONTRIBUTING.md +1 -7
- data/ext/extconf.rb +4 -3
- data/ext/libskylight.yml +5 -6
- data/ext/skylight_native.c +22 -99
- data/lib/skylight.rb +204 -14
- data/lib/skylight/api.rb +7 -3
- data/lib/skylight/cli.rb +4 -3
- data/lib/skylight/cli/doctor.rb +3 -2
- data/lib/skylight/cli/merger.rb +6 -4
- data/lib/skylight/config.rb +603 -126
- data/lib/skylight/deprecation.rb +15 -0
- data/lib/skylight/errors.rb +17 -2
- data/lib/skylight/extensions.rb +99 -0
- data/lib/skylight/extensions/source_location.rb +249 -0
- data/lib/skylight/fanout.rb +0 -0
- data/lib/skylight/formatters/http.rb +19 -0
- data/lib/skylight/gc.rb +109 -0
- data/lib/skylight/helpers.rb +18 -2
- data/lib/skylight/instrumenter.rb +325 -15
- data/lib/skylight/middleware.rb +138 -1
- data/lib/skylight/native.rb +51 -1
- data/lib/skylight/native_ext_fetcher.rb +2 -1
- data/lib/skylight/normalizers.rb +151 -0
- data/lib/skylight/normalizers/action_controller/process_action.rb +69 -0
- data/lib/skylight/normalizers/action_controller/send_file.rb +50 -0
- data/lib/skylight/normalizers/action_dispatch/process_middleware.rb +22 -0
- data/lib/skylight/normalizers/action_dispatch/route_set.rb +27 -0
- data/lib/skylight/normalizers/action_view/render_collection.rb +24 -0
- data/lib/skylight/normalizers/action_view/render_layout.rb +25 -0
- data/lib/skylight/normalizers/action_view/render_partial.rb +23 -0
- data/lib/skylight/normalizers/action_view/render_template.rb +23 -0
- data/lib/skylight/normalizers/active_job/perform.rb +81 -0
- data/lib/skylight/normalizers/active_model_serializers/render.rb +28 -0
- data/lib/skylight/normalizers/active_record/instantiation.rb +16 -0
- data/lib/skylight/normalizers/active_record/sql.rb +12 -0
- data/lib/skylight/normalizers/active_storage.rb +30 -0
- data/lib/skylight/normalizers/active_support/cache.rb +22 -0
- data/lib/skylight/normalizers/active_support/cache_clear.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_decrement.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_delete.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_exist.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_fetch_hit.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_generate.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_increment.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_read.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_read_multi.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_write.rb +16 -0
- data/lib/skylight/normalizers/coach/handler_finish.rb +46 -0
- data/lib/skylight/normalizers/coach/middleware_finish.rb +33 -0
- data/lib/skylight/normalizers/couch_potato/query.rb +20 -0
- data/lib/skylight/normalizers/data_mapper/sql.rb +12 -0
- data/lib/skylight/normalizers/default.rb +32 -0
- data/lib/skylight/normalizers/elasticsearch/request.rb +20 -0
- data/lib/skylight/normalizers/faraday/request.rb +40 -0
- data/lib/skylight/normalizers/grape/endpoint.rb +34 -0
- data/lib/skylight/normalizers/grape/endpoint_render.rb +25 -0
- data/lib/skylight/normalizers/grape/endpoint_run.rb +41 -0
- data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +22 -0
- data/lib/skylight/normalizers/grape/format_response.rb +20 -0
- data/lib/skylight/normalizers/graphiti/render.rb +22 -0
- data/lib/skylight/normalizers/graphiti/resolve.rb +31 -0
- data/lib/skylight/normalizers/graphql/base.rb +131 -0
- data/lib/skylight/normalizers/render.rb +81 -0
- data/lib/skylight/normalizers/sequel/sql.rb +12 -0
- data/lib/skylight/normalizers/sql.rb +44 -0
- data/lib/skylight/probes.rb +153 -0
- data/lib/skylight/probes/action_controller.rb +48 -0
- data/lib/skylight/probes/action_dispatch.rb +2 -0
- data/lib/skylight/probes/action_dispatch/request_id.rb +29 -0
- data/lib/skylight/probes/action_dispatch/routing/route_set.rb +28 -0
- data/lib/skylight/probes/action_view.rb +43 -0
- data/lib/skylight/probes/active_job.rb +29 -0
- data/lib/skylight/probes/active_job_enqueue.rb +37 -0
- data/lib/skylight/probes/active_model_serializers.rb +54 -0
- data/lib/skylight/probes/delayed_job.rb +62 -0
- data/lib/skylight/probes/elasticsearch.rb +38 -0
- data/lib/skylight/probes/excon.rb +25 -0
- data/lib/skylight/probes/excon/middleware.rb +66 -0
- data/lib/skylight/probes/faraday.rb +23 -0
- data/lib/skylight/probes/graphql.rb +43 -0
- data/lib/skylight/probes/httpclient.rb +44 -0
- data/lib/skylight/probes/middleware.rb +125 -0
- data/lib/skylight/probes/mongo.rb +163 -0
- data/lib/skylight/probes/mongoid.rb +13 -0
- data/lib/skylight/probes/net_http.rb +55 -0
- data/lib/skylight/probes/redis.rb +60 -0
- data/lib/skylight/probes/sequel.rb +33 -0
- data/lib/skylight/probes/sinatra.rb +63 -0
- data/lib/skylight/probes/sinatra_add_middleware.rb +10 -10
- data/lib/skylight/probes/tilt.rb +27 -0
- data/lib/skylight/railtie.rb +162 -18
- data/lib/skylight/sidekiq.rb +43 -0
- data/lib/skylight/subscriber.rb +110 -0
- data/lib/skylight/test.rb +146 -0
- data/lib/skylight/trace.rb +301 -10
- data/lib/skylight/user_config.rb +61 -0
- data/lib/skylight/util.rb +12 -0
- data/lib/skylight/util/allocation_free.rb +26 -0
- data/lib/skylight/util/clock.rb +56 -0
- data/lib/skylight/util/component.rb +5 -2
- data/lib/skylight/util/deploy.rb +4 -4
- data/lib/skylight/util/gzip.rb +20 -0
- data/lib/skylight/util/http.rb +4 -10
- data/lib/skylight/util/instrumenter_method.rb +26 -0
- data/lib/skylight/util/logging.rb +138 -0
- data/lib/skylight/util/lru_cache.rb +42 -0
- data/lib/skylight/vendor/cli/thor/rake_compat.rb +1 -1
- data/lib/skylight/version.rb +5 -1
- data/lib/skylight/vm/gc.rb +68 -0
- metadata +110 -11
data/lib/skylight/trace.rb
CHANGED
|
@@ -1,9 +1,52 @@
|
|
|
1
|
+
require "securerandom"
|
|
2
|
+
require "skylight/util/logging"
|
|
3
|
+
|
|
1
4
|
module Skylight
|
|
2
|
-
class Trace
|
|
3
|
-
|
|
5
|
+
class Trace
|
|
6
|
+
GC_CAT = "noise.gc".freeze
|
|
7
|
+
|
|
8
|
+
META_KEYS = %i[mute_children].freeze
|
|
9
|
+
|
|
10
|
+
include Util::Logging
|
|
11
|
+
|
|
12
|
+
attr_reader :instrumenter, :endpoint, :segment, :notifications, :meta, :component
|
|
13
|
+
|
|
14
|
+
def self.new(instrumenter, endpoint, start, cat, title = nil, desc = nil, meta: nil, segment: nil, component: nil)
|
|
15
|
+
uuid = SecureRandom.uuid
|
|
16
|
+
inst = native_new(normalize_time(start), uuid, endpoint, meta)
|
|
17
|
+
inst.uuid = uuid
|
|
18
|
+
inst.send(:initialize, instrumenter, cat, title, desc, meta, component: component)
|
|
19
|
+
inst.endpoint = endpoint
|
|
20
|
+
inst.segment = segment
|
|
21
|
+
inst
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# TODO: Move this into native
|
|
25
|
+
def self.normalize_time(time)
|
|
26
|
+
# At least one customer has extensions that cause integer division to produce rationals.
|
|
27
|
+
# Since the native code expects an integer, we force it again.
|
|
28
|
+
(time.to_i / 100_000).to_i
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def initialize(instrumenter, cat, title, desc, meta, component: nil)
|
|
32
|
+
raise ArgumentError, "instrumenter is required" unless instrumenter
|
|
33
|
+
|
|
34
|
+
@instrumenter = instrumenter
|
|
35
|
+
@submitted = false
|
|
36
|
+
@broken = false
|
|
37
|
+
|
|
38
|
+
@notifications = []
|
|
39
|
+
|
|
40
|
+
@spans = []
|
|
41
|
+
|
|
42
|
+
# create the root node
|
|
43
|
+
@root = start(native_get_started_at, cat, title, desc, meta, normalize: false)
|
|
44
|
+
|
|
45
|
+
# Also store meta for later access
|
|
46
|
+
@meta = meta
|
|
47
|
+
|
|
48
|
+
@gc = config.gc.track unless ENV.key?("SKYLIGHT_DISABLE_GC_TRACKING")
|
|
4
49
|
|
|
5
|
-
def initialize(*, component: nil)
|
|
6
|
-
super
|
|
7
50
|
self.component = component if component
|
|
8
51
|
@too_many_spans = false
|
|
9
52
|
native_use_pruning if use_pruning?
|
|
@@ -26,29 +69,247 @@ module Skylight
|
|
|
26
69
|
!!@too_many_spans
|
|
27
70
|
end
|
|
28
71
|
|
|
29
|
-
def
|
|
30
|
-
|
|
72
|
+
def log_context
|
|
73
|
+
@log_context ||= { trace: uuid }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def endpoint=(value)
|
|
77
|
+
if muted?
|
|
78
|
+
maybe_warn(:endpoint_set_muted, "tried to set endpoint name while muted")
|
|
79
|
+
return
|
|
80
|
+
end
|
|
81
|
+
@endpoint = value
|
|
82
|
+
native_set_endpoint(value)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def segment=(value)
|
|
86
|
+
if muted?
|
|
87
|
+
maybe_warn(:segment_set_muted, "tried to set segment name while muted")
|
|
88
|
+
return
|
|
89
|
+
end
|
|
90
|
+
@segment = value
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
attr_accessor :compound_response_error_status
|
|
94
|
+
|
|
95
|
+
def config
|
|
96
|
+
@instrumenter.config
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def muted?
|
|
100
|
+
!!@child_instrumentation_muted_by || @instrumenter.muted?
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def broken?
|
|
104
|
+
!!@broken
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def maybe_broken(err)
|
|
108
|
+
if err.is_a?(Skylight::MaximumTraceSpansError) && config.get(:report_max_spans_exceeded)
|
|
31
109
|
too_many_spans!
|
|
32
110
|
else
|
|
33
|
-
|
|
111
|
+
error "failed to instrument span; msg=%s; endpoint=%s", err.message, endpoint
|
|
112
|
+
broken!
|
|
34
113
|
end
|
|
35
114
|
end
|
|
36
115
|
|
|
116
|
+
def instrument(cat, title = nil, desc = nil, meta = nil)
|
|
117
|
+
return if muted?
|
|
118
|
+
return if broken?
|
|
119
|
+
|
|
120
|
+
t { "instrument: #{cat}, #{title}" }
|
|
121
|
+
|
|
122
|
+
title.freeze if title.is_a?(String)
|
|
123
|
+
desc.freeze if desc.is_a?(String)
|
|
124
|
+
|
|
125
|
+
now = Skylight::Util::Clock.nanos
|
|
126
|
+
|
|
127
|
+
preprocess_meta(meta) if meta
|
|
128
|
+
|
|
129
|
+
start(now - gc_time, cat, title, desc, meta)
|
|
130
|
+
rescue => e
|
|
131
|
+
maybe_broken(e)
|
|
132
|
+
nil
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def done(span, meta = nil)
|
|
136
|
+
# `span` will be `nil` if we failed to start instrumenting, such as in
|
|
137
|
+
# the case of too many spans in a request.
|
|
138
|
+
return unless span
|
|
139
|
+
return if broken?
|
|
140
|
+
|
|
141
|
+
if meta&.[](:defer)
|
|
142
|
+
deferred_spans[span] ||= (Skylight::Util::Clock.nanos - gc_time)
|
|
143
|
+
return
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
if meta && (meta[:exception_object] || meta[:exception])
|
|
147
|
+
native_span_set_exception(span, meta[:exception_object], meta[:exception])
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
stop(span, Skylight::Util::Clock.nanos - gc_time)
|
|
151
|
+
rescue => e
|
|
152
|
+
error "failed to close span; msg=%s; endpoint=%s", e.message, endpoint
|
|
153
|
+
log_trace "Original Backtrace:\n#{e.backtrace.join("\n")}"
|
|
154
|
+
broken!
|
|
155
|
+
nil
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def inspect
|
|
159
|
+
to_s
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def release
|
|
163
|
+
t { "release; is_current=#{@instrumenter.current_trace == self}" }
|
|
164
|
+
return unless @instrumenter.current_trace == self
|
|
165
|
+
|
|
166
|
+
@instrumenter.current_trace = nil
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def broken!
|
|
170
|
+
debug "trace is broken"
|
|
171
|
+
@broken = true
|
|
172
|
+
end
|
|
173
|
+
|
|
37
174
|
def traced
|
|
38
175
|
if too_many_spans?
|
|
39
176
|
error("[E%04d] The request exceeded the maximum number of spans allowed. It will still " \
|
|
40
177
|
"be tracked but with reduced information. endpoint=%s", Skylight::MaximumTraceSpansError.code, endpoint)
|
|
41
178
|
end
|
|
42
179
|
|
|
43
|
-
|
|
180
|
+
gc = gc_time
|
|
181
|
+
now = Skylight::Util::Clock.nanos
|
|
182
|
+
track_gc(gc, now)
|
|
183
|
+
stop(@root, now)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def submit
|
|
187
|
+
t { "submitting trace" }
|
|
188
|
+
|
|
189
|
+
# This must always be called to clean up properly
|
|
190
|
+
release
|
|
191
|
+
|
|
192
|
+
if broken?
|
|
193
|
+
t { "broken, not submitting" }
|
|
194
|
+
return
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
if @submitted
|
|
198
|
+
t { "already submitted" }
|
|
199
|
+
return
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
@submitted = true
|
|
203
|
+
|
|
204
|
+
traced
|
|
205
|
+
|
|
206
|
+
@instrumenter.process(self)
|
|
207
|
+
rescue Exception => e
|
|
208
|
+
error e.message
|
|
209
|
+
t { e.backtrace.join("\n") }
|
|
44
210
|
end
|
|
45
211
|
|
|
46
212
|
private
|
|
47
213
|
|
|
48
|
-
def track_gc(
|
|
214
|
+
def track_gc(time, now)
|
|
49
215
|
# This attempts to log another span which will fail if we have too many
|
|
50
216
|
return if too_many_spans?
|
|
51
|
-
|
|
217
|
+
|
|
218
|
+
if time > 0
|
|
219
|
+
t { fmt "tracking GC time; duration=%d", time }
|
|
220
|
+
stop(start(now - time, GC_CAT, nil, nil, nil), now)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def start(time, cat, title, desc, meta, opts = {})
|
|
225
|
+
time = self.class.normalize_time(time) unless opts[:normalize] == false
|
|
226
|
+
|
|
227
|
+
mute_children = meta&.delete(:mute_children)
|
|
228
|
+
|
|
229
|
+
sp = native_start_span(time, cat.to_s)
|
|
230
|
+
native_span_set_title(sp, title.to_s) if title
|
|
231
|
+
native_span_set_description(sp, desc.to_s) if desc
|
|
232
|
+
native_span_set_meta(sp, meta) if meta
|
|
233
|
+
native_span_started(sp)
|
|
234
|
+
|
|
235
|
+
@spans << sp
|
|
236
|
+
t { "started span: #{sp} - #{cat}, #{title}" }
|
|
237
|
+
|
|
238
|
+
if mute_children
|
|
239
|
+
t { "muting child instrumentation for span=#{sp}" }
|
|
240
|
+
mute_child_instrumentation(sp)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
sp
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def mute_child_instrumentation(span)
|
|
247
|
+
@child_instrumentation_muted_by = span
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Middleware spans that were interrupted by a throw/catch should be cached here.
|
|
251
|
+
# keys: span ids
|
|
252
|
+
# values: nsec timestamp at which the span was cached here.
|
|
253
|
+
def deferred_spans
|
|
254
|
+
@deferred_spans ||= {}
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def stop(span, time)
|
|
258
|
+
t { "stopping span: #{span}" }
|
|
259
|
+
|
|
260
|
+
# If `stop` is called for a span that is not the last item in the stack,
|
|
261
|
+
# check to see if the last item has been marked as deferred. If so, close
|
|
262
|
+
# that span first, then try to close the original.
|
|
263
|
+
while deferred_spans[expected = @spans.pop]
|
|
264
|
+
normalized_stop(expected, deferred_spans.delete(expected))
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
handle_unexpected_stop(expected, span) unless span == expected
|
|
268
|
+
|
|
269
|
+
normalized_stop(span, time)
|
|
270
|
+
nil
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def normalized_stop(span, time)
|
|
274
|
+
time = self.class.normalize_time(time)
|
|
275
|
+
native_stop_span(span, time)
|
|
276
|
+
|
|
277
|
+
if @child_instrumentation_muted_by == span
|
|
278
|
+
@child_instrumentation_muted_by = nil # restart instrumenting
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Originally extracted from `stop`.
|
|
283
|
+
# If we attempt to close spans out of order, and it appears to be a middleware issue,
|
|
284
|
+
# disable the middleware probe and mark trace as broken.
|
|
285
|
+
def handle_unexpected_stop(expected, span)
|
|
286
|
+
message = "[E0001] Spans were closed out of order. Expected to see '#{native_span_get_title(expected)}', " \
|
|
287
|
+
"but got '#{native_span_get_title(span)}' instead."
|
|
288
|
+
|
|
289
|
+
if native_span_get_category(span) == "rack.middleware" && Skylight::Probes.installed.key?(:middleware)
|
|
290
|
+
if Skylight::Probes::Middleware::Probe.disabled?
|
|
291
|
+
message << "\nWe disabled the Middleware probe but unfortunately, this didn't solve the issue."
|
|
292
|
+
else
|
|
293
|
+
Skylight::Probes::Middleware::Probe.disable!
|
|
294
|
+
message << "\n#{native_span_get_title(span)} may be a Middleware that doesn't fully conform " \
|
|
295
|
+
"to the Rack SPEC. We've disabled the Middleware probe to see if that resolves the issue."
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
message << "\nThis request will not be tracked. Please contact support@skylight.io for more information."
|
|
300
|
+
|
|
301
|
+
error message
|
|
302
|
+
|
|
303
|
+
t { "expected=#{expected}, actual=#{span}" }
|
|
304
|
+
|
|
305
|
+
broken!
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def gc_time
|
|
309
|
+
return 0 unless @gc
|
|
310
|
+
|
|
311
|
+
@gc.update
|
|
312
|
+
@gc.time
|
|
52
313
|
end
|
|
53
314
|
|
|
54
315
|
def use_pruning?
|
|
@@ -61,9 +322,39 @@ module Skylight
|
|
|
61
322
|
|
|
62
323
|
def component=(component)
|
|
63
324
|
resolve_component(component).tap do |c|
|
|
325
|
+
# Would it be better for the component getter to get from native?
|
|
64
326
|
@component = c
|
|
65
327
|
native_set_component(c)
|
|
66
328
|
end
|
|
67
329
|
end
|
|
330
|
+
|
|
331
|
+
def preprocess_meta(meta)
|
|
332
|
+
validate_meta(meta)
|
|
333
|
+
instrumenter.extensions.trace_preprocess_meta(meta)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def validate_meta(meta)
|
|
337
|
+
unknown_keys = meta.keys - allowed_meta_keys
|
|
338
|
+
if unknown_keys.any?
|
|
339
|
+
warn "Unknown meta keys will be ignored; keys=#{unknown_keys.inspect}"
|
|
340
|
+
unknown_keys.each { |key| meta.delete(key) }
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def allowed_meta_keys
|
|
345
|
+
META_KEYS | instrumenter.extensions.allowed_meta_keys
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def maybe_warn(context, msg)
|
|
349
|
+
return if warnings_silenced?(context)
|
|
350
|
+
|
|
351
|
+
instrumenter.silence_warnings(context)
|
|
352
|
+
|
|
353
|
+
warn(msg)
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def warnings_silenced?(context)
|
|
357
|
+
instrumenter.warnings_silenced?(context)
|
|
358
|
+
end
|
|
68
359
|
end
|
|
69
360
|
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require "yaml"
|
|
2
|
+
require "skylight/errors"
|
|
3
|
+
|
|
4
|
+
module Skylight
|
|
5
|
+
class UserConfig
|
|
6
|
+
attr_accessor :disable_dev_warning, :disable_env_warning
|
|
7
|
+
|
|
8
|
+
def initialize(config)
|
|
9
|
+
@config = config
|
|
10
|
+
@file_path = nil
|
|
11
|
+
reload
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def file_path
|
|
15
|
+
return @file_path if @file_path
|
|
16
|
+
|
|
17
|
+
config_path = @config[:user_config_path] || begin
|
|
18
|
+
require "etc"
|
|
19
|
+
home_dir = ENV["HOME"] || Etc.getpwuid.dir || (ENV["USER"] && File.expand_path("~#{ENV['USER']}"))
|
|
20
|
+
if home_dir
|
|
21
|
+
File.join(home_dir, ".skylight")
|
|
22
|
+
else
|
|
23
|
+
raise ConfigError,
|
|
24
|
+
"The Skylight `user_config_path` must be defined since the home directory cannot be inferred"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
@file_path = File.expand_path(config_path)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def disable_dev_warning?
|
|
32
|
+
disable_dev_warning || ENV["SKYLIGHT_DISABLE_DEV_WARNING"] =~ /^true$/i
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def disable_env_warning?
|
|
36
|
+
disable_env_warning
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def reload
|
|
40
|
+
config = File.exist?(file_path) ? YAML.load_file(file_path) : false
|
|
41
|
+
return unless config
|
|
42
|
+
|
|
43
|
+
self.disable_dev_warning = !!config["disable_dev_warning"]
|
|
44
|
+
self.disable_env_warning = !!config["disable_env_warning"]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def save
|
|
48
|
+
FileUtils.mkdir_p(File.dirname(file_path))
|
|
49
|
+
File.open(file_path, "w") do |f|
|
|
50
|
+
f.puts YAML.dump(to_hash)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def to_hash
|
|
55
|
+
{
|
|
56
|
+
"disable_dev_warning" => disable_dev_warning,
|
|
57
|
+
"disable_env_warning" => disable_env_warning
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
# @api private
|
|
3
|
+
module Util
|
|
4
|
+
# Used from the main lib
|
|
5
|
+
require "skylight/util/allocation_free"
|
|
6
|
+
require "skylight/util/clock"
|
|
7
|
+
require "skylight/util/instrumenter_method"
|
|
8
|
+
|
|
9
|
+
# Used from the CLI
|
|
10
|
+
autoload :Gzip, "skylight/util/gzip"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Util
|
|
3
|
+
# Helpers to reduce memory allocation
|
|
4
|
+
module AllocationFree
|
|
5
|
+
# Find an item in an array without allocation.
|
|
6
|
+
#
|
|
7
|
+
# @param array [Array] the array to search
|
|
8
|
+
# @yield a block called against each item until a match is found
|
|
9
|
+
# @yieldparam item an item from the array
|
|
10
|
+
# @yieldreturn [Boolean] whether `item` matches the criteria
|
|
11
|
+
# return the found item or nil, if nothing found
|
|
12
|
+
def array_find(array)
|
|
13
|
+
i = 0
|
|
14
|
+
|
|
15
|
+
while i < array.size
|
|
16
|
+
item = array[i]
|
|
17
|
+
return item if yield item
|
|
18
|
+
|
|
19
|
+
i += 1
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
nil
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|