skylight 1.7.2 → 2.0.0.beta1
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 +4 -33
- data/ext/extconf.rb +32 -6
- data/ext/libskylight.yml +6 -9
- data/ext/skylight_native.c +49 -18
- data/lib/skylight.rb +35 -1
- data/lib/skylight/api.rb +4 -2
- data/lib/skylight/cli.rb +1 -1
- data/lib/skylight/cli/doctor.rb +6 -4
- data/lib/skylight/config.rb +149 -518
- data/lib/skylight/data/cacert.pem +236 -812
- data/lib/skylight/helpers.rb +5 -1
- data/lib/skylight/instrumenter.rb +10 -241
- data/lib/skylight/middleware.rb +1 -89
- data/lib/skylight/native.rb +8 -6
- data/lib/skylight/native_ext_fetcher.rb +251 -0
- data/lib/skylight/normalizers/active_job/enqueue_at.rb +2 -20
- data/lib/skylight/probes/sinatra_add_middleware.rb +22 -0
- data/lib/skylight/railtie.rb +11 -131
- data/lib/skylight/sinatra.rb +1 -5
- data/lib/skylight/trace.rb +1 -229
- data/lib/skylight/util/http.rb +3 -3
- data/lib/skylight/vendor/cli/thor/actions/directory.rb +5 -15
- data/lib/skylight/version.rb +1 -1
- metadata +114 -91
- data/lib/skylight/compat.rb +0 -76
- data/lib/skylight/core.rb +0 -149
- data/lib/skylight/deprecation.rb +0 -55
- data/lib/skylight/formatters/http.rb +0 -20
- data/lib/skylight/gc.rb +0 -107
- data/lib/skylight/normalizers.rb +0 -192
- data/lib/skylight/normalizers/action_controller/process_action.rb +0 -50
- data/lib/skylight/normalizers/action_controller/send_file.rb +0 -50
- data/lib/skylight/normalizers/action_view/render_collection.rb +0 -22
- data/lib/skylight/normalizers/action_view/render_partial.rb +0 -21
- data/lib/skylight/normalizers/action_view/render_template.rb +0 -21
- data/lib/skylight/normalizers/active_model_serializers/render.rb +0 -26
- data/lib/skylight/normalizers/active_record/instantiation.rb +0 -17
- data/lib/skylight/normalizers/active_record/sql.rb +0 -55
- data/lib/skylight/normalizers/active_support/cache.rb +0 -51
- data/lib/skylight/normalizers/active_support/cache_clear.rb +0 -16
- data/lib/skylight/normalizers/active_support/cache_decrement.rb +0 -16
- data/lib/skylight/normalizers/active_support/cache_delete.rb +0 -16
- data/lib/skylight/normalizers/active_support/cache_exist.rb +0 -16
- data/lib/skylight/normalizers/active_support/cache_fetch_hit.rb +0 -16
- data/lib/skylight/normalizers/active_support/cache_generate.rb +0 -16
- data/lib/skylight/normalizers/active_support/cache_increment.rb +0 -16
- data/lib/skylight/normalizers/active_support/cache_read.rb +0 -16
- data/lib/skylight/normalizers/active_support/cache_read_multi.rb +0 -16
- data/lib/skylight/normalizers/active_support/cache_write.rb +0 -16
- data/lib/skylight/normalizers/coach/handler_finish.rb +0 -36
- data/lib/skylight/normalizers/coach/middleware_finish.rb +0 -23
- data/lib/skylight/normalizers/couch_potato/query.rb +0 -20
- data/lib/skylight/normalizers/default.rb +0 -27
- data/lib/skylight/normalizers/elasticsearch/request.rb +0 -20
- data/lib/skylight/normalizers/faraday/request.rb +0 -38
- data/lib/skylight/normalizers/grape/endpoint.rb +0 -30
- data/lib/skylight/normalizers/grape/endpoint_render.rb +0 -26
- data/lib/skylight/normalizers/grape/endpoint_run.rb +0 -33
- data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +0 -23
- data/lib/skylight/normalizers/moped/query.rb +0 -100
- data/lib/skylight/probes.rb +0 -129
- data/lib/skylight/probes/action_controller.rb +0 -64
- data/lib/skylight/probes/action_dispatch.rb +0 -30
- data/lib/skylight/probes/action_view.rb +0 -43
- data/lib/skylight/probes/active_model_serializers.rb +0 -55
- data/lib/skylight/probes/elasticsearch.rb +0 -37
- data/lib/skylight/probes/excon.rb +0 -26
- data/lib/skylight/probes/excon/middleware.rb +0 -68
- data/lib/skylight/probes/faraday.rb +0 -22
- data/lib/skylight/probes/grape.rb +0 -88
- data/lib/skylight/probes/httpclient.rb +0 -46
- data/lib/skylight/probes/middleware.rb +0 -68
- data/lib/skylight/probes/mongo.rb +0 -161
- data/lib/skylight/probes/mongoid.rb +0 -21
- data/lib/skylight/probes/moped.rb +0 -39
- data/lib/skylight/probes/net_http.rb +0 -58
- data/lib/skylight/probes/redis.rb +0 -71
- data/lib/skylight/probes/sequel.rb +0 -37
- data/lib/skylight/probes/sinatra.rb +0 -76
- data/lib/skylight/probes/tilt.rb +0 -31
- data/lib/skylight/subscriber.rb +0 -122
- data/lib/skylight/user_config.rb +0 -60
- data/lib/skylight/util.rb +0 -17
- data/lib/skylight/util/allocation_free.rb +0 -26
- data/lib/skylight/util/clock.rb +0 -54
- data/lib/skylight/util/deploy.rb +0 -132
- data/lib/skylight/util/gzip.rb +0 -21
- data/lib/skylight/util/inflector.rb +0 -112
- data/lib/skylight/util/logging.rb +0 -127
- data/lib/skylight/util/multi_io.rb +0 -21
- data/lib/skylight/util/native_ext_fetcher.rb +0 -253
- data/lib/skylight/util/platform.rb +0 -75
- data/lib/skylight/util/proxy.rb +0 -13
- data/lib/skylight/vendor/active_support/notifications.rb +0 -207
- data/lib/skylight/vendor/active_support/notifications/fanout.rb +0 -159
- data/lib/skylight/vendor/active_support/notifications/instrumenter.rb +0 -72
- data/lib/skylight/vendor/active_support/per_thread_registry.rb +0 -52
- data/lib/skylight/vendor/thread_safe.rb +0 -126
- data/lib/skylight/vendor/thread_safe/non_concurrent_cache_backend.rb +0 -133
- data/lib/skylight/vendor/thread_safe/synchronized_cache_backend.rb +0 -76
- data/lib/skylight/vm/gc.rb +0 -70
data/lib/skylight/helpers.rb
CHANGED
|
@@ -145,10 +145,14 @@ module Skylight
|
|
|
145
145
|
title: #{title.inspect},
|
|
146
146
|
description: #{desc.inspect})
|
|
147
147
|
|
|
148
|
+
meta = {}
|
|
148
149
|
begin
|
|
149
150
|
send(:before_instrument_#{name}, *args, &blk)
|
|
151
|
+
rescue Exception => e
|
|
152
|
+
meta[:exception_object] = e
|
|
153
|
+
raise e
|
|
150
154
|
ensure
|
|
151
|
-
Skylight.done(span) if span
|
|
155
|
+
Skylight.done(span, meta) if span
|
|
152
156
|
end
|
|
153
157
|
end
|
|
154
158
|
RUBY
|
|
@@ -1,255 +1,24 @@
|
|
|
1
|
-
require 'thread'
|
|
2
|
-
require 'strscan'
|
|
3
|
-
require 'skylight/api'
|
|
4
|
-
|
|
5
1
|
module Skylight
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
LOCK = Mutex.new
|
|
10
|
-
|
|
11
|
-
TOO_MANY_UNIQUES = "<too many unique descriptions>"
|
|
12
|
-
|
|
13
|
-
include Util::Logging
|
|
14
|
-
|
|
15
|
-
class TraceInfo
|
|
16
|
-
def current
|
|
17
|
-
Thread.current[KEY]
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def current=(trace)
|
|
21
|
-
Thread.current[KEY] = trace
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def self.instance
|
|
26
|
-
@instance
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Do start
|
|
30
|
-
# @param [Config] config The config
|
|
31
|
-
def self.start!(config = nil)
|
|
32
|
-
return @instance if @instance
|
|
33
|
-
|
|
34
|
-
LOCK.synchronize do
|
|
35
|
-
return @instance if @instance
|
|
36
|
-
@instance = new(config).start!
|
|
37
|
-
end
|
|
38
|
-
rescue => e
|
|
39
|
-
message = sprintf("[SKYLIGHT] [#{Skylight::VERSION}] Unable to start Instrumenter; msg=%s; class=%s", e.message, e.class)
|
|
40
|
-
if config && config.respond_to?(:logger)
|
|
41
|
-
config.logger.warn message
|
|
42
|
-
else
|
|
43
|
-
warn message
|
|
44
|
-
end
|
|
45
|
-
false
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def self.stop!
|
|
49
|
-
LOCK.synchronize do
|
|
50
|
-
return unless @instance
|
|
51
|
-
# This is only really helpful for getting specs to pass.
|
|
52
|
-
@instance.current_trace = nil
|
|
53
|
-
|
|
54
|
-
@instance.shutdown
|
|
55
|
-
@instance = nil
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
at_exit do
|
|
60
|
-
stop!
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
attr_reader :config, :gc, :trace_info
|
|
64
|
-
|
|
65
|
-
def self.new(config)
|
|
66
|
-
config ||= {}
|
|
67
|
-
config = Config.load(config) unless config.is_a?(Config)
|
|
68
|
-
config.validate!
|
|
69
|
-
|
|
70
|
-
inst = native_new(config.to_native_env)
|
|
71
|
-
inst.send(:initialize, config)
|
|
72
|
-
inst
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def initialize(config)
|
|
76
|
-
@gc = config.gc
|
|
77
|
-
@config = config
|
|
78
|
-
@subscriber = Subscriber.new(config, self)
|
|
79
|
-
|
|
80
|
-
@trace_info = @config[:trace_info] || TraceInfo.new
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def current_trace
|
|
84
|
-
@trace_info.current
|
|
2
|
+
class Instrumenter < Core::Instrumenter
|
|
3
|
+
def self.trace_class
|
|
4
|
+
Trace
|
|
85
5
|
end
|
|
86
6
|
|
|
87
|
-
def
|
|
88
|
-
@trace_info.current = trace
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def start!
|
|
7
|
+
def check_install!
|
|
92
8
|
# Warn if there was an error installing Skylight.
|
|
93
|
-
# We do this here since we can't report these issues via Gem install without stopping install entirely.
|
|
94
|
-
Skylight.check_install_errors(config)
|
|
95
|
-
|
|
96
|
-
unless Skylight.native?
|
|
97
|
-
Skylight.warn_skylight_native_missing(config)
|
|
98
|
-
return
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
t { "starting instrumenter" }
|
|
102
|
-
|
|
103
|
-
unless config.validate_with_server
|
|
104
|
-
log_error "invalid config"
|
|
105
|
-
return
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
t { "starting native instrumenter" }
|
|
109
|
-
unless native_start
|
|
110
|
-
warn "failed to start instrumenter"
|
|
111
|
-
return
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
config.gc.enable
|
|
115
|
-
@subscriber.register!
|
|
116
|
-
|
|
117
|
-
self
|
|
118
|
-
|
|
119
|
-
rescue Exception => e
|
|
120
|
-
log_error "failed to start instrumenter; msg=%s; config=%s", e.message, config.inspect
|
|
121
|
-
t { e.backtrace.join("\n") }
|
|
122
|
-
nil
|
|
123
|
-
end
|
|
124
9
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
native_stop
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def trace(endpoint, cat, title=nil, desc=nil)
|
|
131
|
-
# If a trace is already in progress, continue with that one
|
|
132
|
-
if trace = @trace_info.current
|
|
133
|
-
return yield(trace) if block_given?
|
|
134
|
-
return trace
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
begin
|
|
138
|
-
trace = Trace.new(self, endpoint, Util::Clock.nanos, cat, title, desc)
|
|
139
|
-
rescue Exception => e
|
|
140
|
-
log_error e.message
|
|
141
|
-
t { e.backtrace.join("\n") }
|
|
142
|
-
return
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
@trace_info.current = trace
|
|
146
|
-
return trace unless block_given?
|
|
147
|
-
|
|
148
|
-
begin
|
|
149
|
-
yield trace
|
|
150
|
-
|
|
151
|
-
ensure
|
|
152
|
-
@trace_info.current = nil
|
|
153
|
-
t { "submitting trace" }
|
|
154
|
-
trace.submit
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def disable
|
|
159
|
-
@disabled = true
|
|
160
|
-
yield
|
|
161
|
-
ensure
|
|
162
|
-
@disabled = false
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
def disabled?
|
|
166
|
-
@disabled
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
@scanner = StringScanner.new('')
|
|
170
|
-
def self.match?(string, regex)
|
|
171
|
-
@scanner.string = string
|
|
172
|
-
@scanner.match?(regex)
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def match?(string, regex)
|
|
176
|
-
self.class.match?(string, regex)
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
def done(span)
|
|
180
|
-
return unless trace = @trace_info.current
|
|
181
|
-
trace.done(span)
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def broken!
|
|
185
|
-
return unless trace = @trace_info.current
|
|
186
|
-
trace.broken!
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
def instrument(cat, title=nil, desc=nil)
|
|
190
|
-
raise ArgumentError, 'cat is required' unless cat
|
|
191
|
-
|
|
192
|
-
unless trace = @trace_info.current
|
|
193
|
-
return yield if block_given?
|
|
194
|
-
return
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
cat = cat.to_s
|
|
198
|
-
|
|
199
|
-
unless match?(cat, CATEGORY_REGEX)
|
|
200
|
-
warn "invalid skylight instrumentation category; value=%s", cat
|
|
201
|
-
return yield if block_given?
|
|
202
|
-
return
|
|
10
|
+
if defined?(Skylight.check_install_errors)
|
|
11
|
+
Skylight.check_install_errors(config)
|
|
203
12
|
end
|
|
204
13
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
unless sp = trace.instrument(cat, title, desc)
|
|
208
|
-
return yield if block_given?
|
|
14
|
+
if !Skylight.native? && defined?(Skylight.warn_skylight_native_missing)
|
|
15
|
+
Skylight.warn_skylight_native_missing(config)
|
|
209
16
|
return
|
|
210
17
|
end
|
|
211
|
-
|
|
212
|
-
return sp unless block_given?
|
|
213
|
-
|
|
214
|
-
begin
|
|
215
|
-
yield sp
|
|
216
|
-
ensure
|
|
217
|
-
trace.done(sp)
|
|
218
|
-
end
|
|
219
18
|
end
|
|
220
19
|
|
|
221
|
-
def
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if description
|
|
225
|
-
if native_track_desc(endpoint, description)
|
|
226
|
-
description
|
|
227
|
-
else
|
|
228
|
-
TOO_MANY_UNIQUES
|
|
229
|
-
end
|
|
230
|
-
end
|
|
20
|
+
def process_sql(sql)
|
|
21
|
+
Skylight.lex_sql(sql, config[:use_old_sql_lexer])
|
|
231
22
|
end
|
|
232
|
-
|
|
233
|
-
def process(trace)
|
|
234
|
-
t { fmt "processing trace" }
|
|
235
|
-
|
|
236
|
-
if ignore?(trace)
|
|
237
|
-
t { fmt "ignoring trace" }
|
|
238
|
-
return false
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
begin
|
|
242
|
-
native_submit_trace(trace)
|
|
243
|
-
true
|
|
244
|
-
rescue => e
|
|
245
|
-
warn "failed to submit trace to worker; err=%s", e
|
|
246
|
-
false
|
|
247
|
-
end
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
def ignore?(trace)
|
|
251
|
-
config.ignored_endpoints.include?(trace.endpoint.sub(%r{<sk-segment>.+</sk-segment>}, ''))
|
|
252
|
-
end
|
|
253
|
-
|
|
254
23
|
end
|
|
255
24
|
end
|
data/lib/skylight/middleware.rb
CHANGED
|
@@ -1,92 +1,4 @@
|
|
|
1
1
|
module Skylight
|
|
2
|
-
|
|
3
|
-
class Middleware
|
|
4
|
-
|
|
5
|
-
class BodyProxy
|
|
6
|
-
def initialize(body, &block)
|
|
7
|
-
@body, @block, @closed = body, block, false
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def respond_to?(*args)
|
|
11
|
-
return false if args.first.to_s =~ /^to_ary$/
|
|
12
|
-
super or @body.respond_to?(*args)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def close
|
|
16
|
-
return if @closed
|
|
17
|
-
@closed = true
|
|
18
|
-
begin
|
|
19
|
-
@body.close if @body.respond_to? :close
|
|
20
|
-
ensure
|
|
21
|
-
@block.call
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def closed?
|
|
26
|
-
@closed
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# N.B. This method is a special case to address the bug described by
|
|
30
|
-
# https://github.com/rack/rack/issues/434.
|
|
31
|
-
# We are applying this special case for #each only. Future bugs of this
|
|
32
|
-
# class will be handled by requesting users to patch their ruby
|
|
33
|
-
# implementation, to save adding too many methods in this class.
|
|
34
|
-
def each(*args, &block)
|
|
35
|
-
@body.each(*args, &block)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def method_missing(*args, &block)
|
|
39
|
-
super if args.first.to_s =~ /^to_ary$/
|
|
40
|
-
@body.__send__(*args, &block)
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def self.with_after_close(resp, &block)
|
|
45
|
-
# Responses should be arrays but in some situations they aren't
|
|
46
|
-
# e.g. https://github.com/ruby-grape/grape/issues/1041
|
|
47
|
-
# The safest approach seems to be to rely on implicit destructuring
|
|
48
|
-
# since that is currently what Rack::Lint does.
|
|
49
|
-
# See also https://github.com/rack/rack/issues/1239
|
|
50
|
-
status, headers, body = resp
|
|
51
|
-
|
|
52
|
-
[status, headers, BodyProxy.new(body, &block)]
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
include Util::Logging
|
|
56
|
-
|
|
57
|
-
# For Util::Logging
|
|
58
|
-
attr_reader :config
|
|
59
|
-
|
|
60
|
-
def initialize(app, opts={})
|
|
61
|
-
@app = app
|
|
62
|
-
@config = opts[:config]
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def call(env)
|
|
66
|
-
if Skylight.tracing?
|
|
67
|
-
error "Already instrumenting. Make sure the Middleware hasn't been added more than once."
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
if env["REQUEST_METHOD"] == "HEAD"
|
|
71
|
-
t { "middleware skipping HEAD" }
|
|
72
|
-
@app.call(env)
|
|
73
|
-
else
|
|
74
|
-
begin
|
|
75
|
-
t { "middleware beginning trace" }
|
|
76
|
-
trace = Skylight.trace "Rack", 'app.rack.request'
|
|
77
|
-
resp = @app.call(env)
|
|
78
|
-
|
|
79
|
-
if trace
|
|
80
|
-
Middleware.with_after_close(resp) { trace.submit }
|
|
81
|
-
else
|
|
82
|
-
resp
|
|
83
|
-
end
|
|
84
|
-
rescue Exception
|
|
85
|
-
t { "middleware exception: #{trace}"}
|
|
86
|
-
trace.submit if trace
|
|
87
|
-
raise
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
end
|
|
2
|
+
class Middleware < Core::Middleware
|
|
91
3
|
end
|
|
92
4
|
end
|
data/lib/skylight/native.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require 'skylight/util/platform'
|
|
1
|
+
require 'skylight/core/util/platform'
|
|
2
2
|
|
|
3
3
|
module Skylight
|
|
4
4
|
# @api private
|
|
@@ -10,14 +10,14 @@ module Skylight
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def self.libskylight_path
|
|
13
|
-
ENV['SKYLIGHT_LIB_PATH'] || File.expand_path("../native/#{Util::Platform.tuple}", __FILE__)
|
|
13
|
+
ENV['SKYLIGHT_LIB_PATH'] || File.expand_path("../native/#{Core::Util::Platform.tuple}", __FILE__)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
skylight_required = ENV.key?("SKYLIGHT_REQUIRED") && ENV['SKYLIGHT_REQUIRED'] !~ /^false$/i
|
|
17
17
|
|
|
18
18
|
begin
|
|
19
19
|
unless ENV.key?("SKYLIGHT_DISABLE_AGENT") && ENV['SKYLIGHT_DISABLE_AGENT'] !~ /^false$/i
|
|
20
|
-
lib = "#{libskylight_path}/libskylight.#{Util::Platform.libext}"
|
|
20
|
+
lib = "#{libskylight_path}/libskylight.#{Core::Util::Platform.libext}"
|
|
21
21
|
|
|
22
22
|
if File.exist?(lib)
|
|
23
23
|
# First attempt to require the native extension
|
|
@@ -39,7 +39,9 @@ module Skylight
|
|
|
39
39
|
raise if skylight_required
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
if Skylight.native?
|
|
43
|
+
Skylight::Core::Util::Clock.use_native!
|
|
44
|
+
else
|
|
43
45
|
class Instrumenter
|
|
44
46
|
def self.native_new(*args)
|
|
45
47
|
allocate
|
|
@@ -54,7 +56,7 @@ module Skylight
|
|
|
54
56
|
|
|
55
57
|
if File.exist?(install_log) && File.read(install_log) =~ /ERROR/
|
|
56
58
|
config.alert_logger.error \
|
|
57
|
-
"[SKYLIGHT] [#{Skylight::VERSION}] The Skylight native extension failed to install. " \
|
|
59
|
+
"[SKYLIGHT] [#{Skylight::Core::VERSION}] The Skylight native extension failed to install. " \
|
|
58
60
|
"Please check #{install_log} and notify support@skylight.io. " \
|
|
59
61
|
"The missing extension will not affect the functioning of your application."
|
|
60
62
|
end
|
|
@@ -63,7 +65,7 @@ module Skylight
|
|
|
63
65
|
# @api private
|
|
64
66
|
def self.warn_skylight_native_missing(config)
|
|
65
67
|
config.alert_logger.error \
|
|
66
|
-
"[SKYLIGHT] [#{Skylight::VERSION}] The Skylight native extension for " \
|
|
68
|
+
"[SKYLIGHT] [#{Skylight::Core::VERSION}] The Skylight native extension for " \
|
|
67
69
|
"your platform wasn't found. Supported operating systems are " \
|
|
68
70
|
"Linux 2.6.18+ and Mac OS X 10.8+. The missing extension will not " \
|
|
69
71
|
"affect the functioning of your application. If you are on a " \
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
require 'logger'
|
|
3
|
+
require 'net/http'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
require 'digest/sha2'
|
|
6
|
+
require 'skylight/util/ssl'
|
|
7
|
+
require 'skylight/core/util/proxy'
|
|
8
|
+
|
|
9
|
+
# Used from extconf.rb
|
|
10
|
+
module Skylight
|
|
11
|
+
# Utility class for fetching the native extension from a URL
|
|
12
|
+
class NativeExtFetcher
|
|
13
|
+
BASE_URL = "https://s3.amazonaws.com/skylight-agent-packages/skylight-native"
|
|
14
|
+
MAX_REDIRECTS = 5
|
|
15
|
+
MAX_RETRIES = 3
|
|
16
|
+
|
|
17
|
+
include FileUtils
|
|
18
|
+
|
|
19
|
+
class FetchError < StandardError; end
|
|
20
|
+
|
|
21
|
+
# Creates a new fetcher and fetches
|
|
22
|
+
# @param opts [Hash]
|
|
23
|
+
def self.fetch(opts = {})
|
|
24
|
+
fetcher = new(
|
|
25
|
+
opts[:source] || BASE_URL,
|
|
26
|
+
opts[:target],
|
|
27
|
+
opts[:version],
|
|
28
|
+
opts[:checksum],
|
|
29
|
+
opts[:arch],
|
|
30
|
+
opts[:required],
|
|
31
|
+
opts[:platform],
|
|
32
|
+
opts[:logger] || Logger.new(STDOUT))
|
|
33
|
+
|
|
34
|
+
fetcher.fetch
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @param source [String] the base url to download from
|
|
38
|
+
# @param target [String] file to download as
|
|
39
|
+
# @param version [String] version to download
|
|
40
|
+
# @param checksum [String] checksum of the archive
|
|
41
|
+
# @param arch [String] platform architecture, e.g. `linux-x86_64`
|
|
42
|
+
# @param required [Boolean] whether the download is required to be successful
|
|
43
|
+
# @param platform
|
|
44
|
+
# @param log [Logger]
|
|
45
|
+
def initialize(source, target, version, checksum, arch, required, platform, log)
|
|
46
|
+
raise "source required" unless source
|
|
47
|
+
raise "target required" unless target
|
|
48
|
+
raise "checksum required" unless checksum
|
|
49
|
+
raise "arch required" unless arch
|
|
50
|
+
|
|
51
|
+
@source = source
|
|
52
|
+
@target = target
|
|
53
|
+
@version = version
|
|
54
|
+
@checksum = checksum
|
|
55
|
+
@required = required
|
|
56
|
+
@platform = platform
|
|
57
|
+
@arch = arch
|
|
58
|
+
@log = log
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Fetch the native extension, verify, inflate, and save (if applicable)
|
|
62
|
+
#
|
|
63
|
+
# @return [String] the inflated archive
|
|
64
|
+
def fetch
|
|
65
|
+
log "fetching native ext; curr-platform=#{@platform}; " \
|
|
66
|
+
"requested-arch=#{@arch}; version=#{@version}"
|
|
67
|
+
|
|
68
|
+
tar_gz = "#{@target}/#{basename}"
|
|
69
|
+
|
|
70
|
+
unless sha2 = fetch_native_ext(source_uri, tar_gz, MAX_RETRIES, MAX_REDIRECTS)
|
|
71
|
+
maybe_raise "could not fetch native extension"
|
|
72
|
+
return
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
unless verify_checksum(sha2)
|
|
76
|
+
maybe_raise "could not verify checksum"
|
|
77
|
+
return
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
Dir.chdir File.dirname(tar_gz) do
|
|
81
|
+
system "tar xzvf #{tar_gz}"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
true
|
|
85
|
+
ensure
|
|
86
|
+
rm_f tar_gz if tar_gz
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def fetch_native_ext(uri, out, attempts, redirects)
|
|
90
|
+
redirects.times do |i|
|
|
91
|
+
# Ensure the location is available
|
|
92
|
+
mkdir_p File.dirname(out)
|
|
93
|
+
rm_f out
|
|
94
|
+
|
|
95
|
+
remaining_attempts = attempts
|
|
96
|
+
|
|
97
|
+
log "attempting to fetch from remote; uri=#{uri}"
|
|
98
|
+
|
|
99
|
+
begin
|
|
100
|
+
host, port, use_ssl, path = deconstruct_uri(uri)
|
|
101
|
+
|
|
102
|
+
File.open out, 'w' do |f|
|
|
103
|
+
res, extra = http_get(host, port, use_ssl, path, f)
|
|
104
|
+
|
|
105
|
+
case res
|
|
106
|
+
when :success
|
|
107
|
+
log "successfully downloaded native ext; out=#{out}"
|
|
108
|
+
return extra
|
|
109
|
+
when :redirect
|
|
110
|
+
log "fetching native ext; uri=#{uri}; redirected=#{res}"
|
|
111
|
+
uri = extra
|
|
112
|
+
|
|
113
|
+
next
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
rescue => e
|
|
117
|
+
remaining_attempts -= 1
|
|
118
|
+
|
|
119
|
+
error "failed to fetch native extension; uri=#{uri}; msg=#{e.message}; remaining-attempts=#{remaining_attempts}", e
|
|
120
|
+
|
|
121
|
+
if remaining_attempts > 0
|
|
122
|
+
sleep 2
|
|
123
|
+
retry
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
return
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
log "exceeded max redirects"
|
|
131
|
+
return
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Get with `Net::HTTP`
|
|
135
|
+
#
|
|
136
|
+
# @param host [String] host for `Net::HTTP` request
|
|
137
|
+
# @param port [String,Integer] port for `Net::HTTP` request
|
|
138
|
+
# @param use_ssl [Boolean] whether SSL should be used for this request
|
|
139
|
+
# @param path [String] the path to request
|
|
140
|
+
# @param out [IO]
|
|
141
|
+
#
|
|
142
|
+
# If `ENV['HTTP_PROXY']` is set, it will be used as a proxy for this request.
|
|
143
|
+
def http_get(host, port, use_ssl, path, out)
|
|
144
|
+
if http_proxy = Core::Util::Proxy.detect_url(ENV)
|
|
145
|
+
log "connecting with proxy: #{http_proxy}"
|
|
146
|
+
uri = URI.parse(http_proxy)
|
|
147
|
+
p_host, p_port = uri.host, uri.port
|
|
148
|
+
p_user, p_pass = uri.userinfo.split(/:/) if uri.userinfo
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
opts = {}
|
|
152
|
+
opts[:use_ssl] = use_ssl
|
|
153
|
+
|
|
154
|
+
if use_ssl
|
|
155
|
+
opts[:ca_file] = Util::SSL.ca_cert_file_or_default
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
Net::HTTP.start(host, port, p_host, p_port, p_user, p_pass, use_ssl: use_ssl) do |http|
|
|
159
|
+
http.request_get path do |resp|
|
|
160
|
+
case resp
|
|
161
|
+
when Net::HTTPSuccess
|
|
162
|
+
digest = Digest::SHA2.new
|
|
163
|
+
|
|
164
|
+
resp.read_body do |chunk|
|
|
165
|
+
digest << chunk
|
|
166
|
+
out.write chunk
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
return [ :success, digest.hexdigest ]
|
|
170
|
+
when Net::HTTPRedirection
|
|
171
|
+
unless location = resp['location']
|
|
172
|
+
raise "received redirect but no location"
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
return [ :redirect, location ]
|
|
176
|
+
else
|
|
177
|
+
raise "received HTTP status code #{resp.code}"
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Verify the checksum of the archive
|
|
184
|
+
#
|
|
185
|
+
# @param actual [String]
|
|
186
|
+
# @return [Boolean] whether the checksum matches
|
|
187
|
+
def verify_checksum(actual)
|
|
188
|
+
unless @checksum == actual
|
|
189
|
+
log "checksum mismatch; expected=#{@checksum}; actual=#{actual}"
|
|
190
|
+
return false
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
true
|
|
194
|
+
rescue Exception => e
|
|
195
|
+
error "failed to read skylight agent archive; e=#{e.message}"
|
|
196
|
+
false
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def basename
|
|
200
|
+
"skylight_#{@arch}.tar.gz"
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# The url that will be fetched
|
|
204
|
+
#
|
|
205
|
+
# @return String
|
|
206
|
+
def source_uri
|
|
207
|
+
"#{@source}/#{@version}/#{basename}"
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Split the uri string into its component parts
|
|
211
|
+
#
|
|
212
|
+
# @param uri [String] the uri
|
|
213
|
+
# @return [Array<String>] the host, port, scheme, and request_uri
|
|
214
|
+
def deconstruct_uri(uri)
|
|
215
|
+
uri = URI(uri)
|
|
216
|
+
[ uri.host, uri.port, uri.scheme == 'https', uri.request_uri ]
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Log an error and raise if `required` is `true`
|
|
220
|
+
#
|
|
221
|
+
# @param err [String]
|
|
222
|
+
# @return [void]
|
|
223
|
+
def maybe_raise(err)
|
|
224
|
+
error err
|
|
225
|
+
|
|
226
|
+
if @required
|
|
227
|
+
raise err
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Log an `info` to the `logger`
|
|
232
|
+
#
|
|
233
|
+
# @param msg [String]
|
|
234
|
+
# @return [void]
|
|
235
|
+
def log(msg)
|
|
236
|
+
msg = "[SKYLIGHT] #{msg}"
|
|
237
|
+
@log.info msg
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Log an `error` to the `logger`
|
|
241
|
+
#
|
|
242
|
+
# @param msg [String]
|
|
243
|
+
# @param e [Exception] the exception associated with the error
|
|
244
|
+
# @return [void]
|
|
245
|
+
def error(msg, e=nil)
|
|
246
|
+
msg = "[SKYLIGHT] #{msg}"
|
|
247
|
+
msg << "\n#{e.backtrace.join("\n")}" if e
|
|
248
|
+
@log.error msg
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|