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.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -33
  3. data/ext/extconf.rb +32 -6
  4. data/ext/libskylight.yml +6 -9
  5. data/ext/skylight_native.c +49 -18
  6. data/lib/skylight.rb +35 -1
  7. data/lib/skylight/api.rb +4 -2
  8. data/lib/skylight/cli.rb +1 -1
  9. data/lib/skylight/cli/doctor.rb +6 -4
  10. data/lib/skylight/config.rb +149 -518
  11. data/lib/skylight/data/cacert.pem +236 -812
  12. data/lib/skylight/helpers.rb +5 -1
  13. data/lib/skylight/instrumenter.rb +10 -241
  14. data/lib/skylight/middleware.rb +1 -89
  15. data/lib/skylight/native.rb +8 -6
  16. data/lib/skylight/native_ext_fetcher.rb +251 -0
  17. data/lib/skylight/normalizers/active_job/enqueue_at.rb +2 -20
  18. data/lib/skylight/probes/sinatra_add_middleware.rb +22 -0
  19. data/lib/skylight/railtie.rb +11 -131
  20. data/lib/skylight/sinatra.rb +1 -5
  21. data/lib/skylight/trace.rb +1 -229
  22. data/lib/skylight/util/http.rb +3 -3
  23. data/lib/skylight/vendor/cli/thor/actions/directory.rb +5 -15
  24. data/lib/skylight/version.rb +1 -1
  25. metadata +114 -91
  26. data/lib/skylight/compat.rb +0 -76
  27. data/lib/skylight/core.rb +0 -149
  28. data/lib/skylight/deprecation.rb +0 -55
  29. data/lib/skylight/formatters/http.rb +0 -20
  30. data/lib/skylight/gc.rb +0 -107
  31. data/lib/skylight/normalizers.rb +0 -192
  32. data/lib/skylight/normalizers/action_controller/process_action.rb +0 -50
  33. data/lib/skylight/normalizers/action_controller/send_file.rb +0 -50
  34. data/lib/skylight/normalizers/action_view/render_collection.rb +0 -22
  35. data/lib/skylight/normalizers/action_view/render_partial.rb +0 -21
  36. data/lib/skylight/normalizers/action_view/render_template.rb +0 -21
  37. data/lib/skylight/normalizers/active_model_serializers/render.rb +0 -26
  38. data/lib/skylight/normalizers/active_record/instantiation.rb +0 -17
  39. data/lib/skylight/normalizers/active_record/sql.rb +0 -55
  40. data/lib/skylight/normalizers/active_support/cache.rb +0 -51
  41. data/lib/skylight/normalizers/active_support/cache_clear.rb +0 -16
  42. data/lib/skylight/normalizers/active_support/cache_decrement.rb +0 -16
  43. data/lib/skylight/normalizers/active_support/cache_delete.rb +0 -16
  44. data/lib/skylight/normalizers/active_support/cache_exist.rb +0 -16
  45. data/lib/skylight/normalizers/active_support/cache_fetch_hit.rb +0 -16
  46. data/lib/skylight/normalizers/active_support/cache_generate.rb +0 -16
  47. data/lib/skylight/normalizers/active_support/cache_increment.rb +0 -16
  48. data/lib/skylight/normalizers/active_support/cache_read.rb +0 -16
  49. data/lib/skylight/normalizers/active_support/cache_read_multi.rb +0 -16
  50. data/lib/skylight/normalizers/active_support/cache_write.rb +0 -16
  51. data/lib/skylight/normalizers/coach/handler_finish.rb +0 -36
  52. data/lib/skylight/normalizers/coach/middleware_finish.rb +0 -23
  53. data/lib/skylight/normalizers/couch_potato/query.rb +0 -20
  54. data/lib/skylight/normalizers/default.rb +0 -27
  55. data/lib/skylight/normalizers/elasticsearch/request.rb +0 -20
  56. data/lib/skylight/normalizers/faraday/request.rb +0 -38
  57. data/lib/skylight/normalizers/grape/endpoint.rb +0 -30
  58. data/lib/skylight/normalizers/grape/endpoint_render.rb +0 -26
  59. data/lib/skylight/normalizers/grape/endpoint_run.rb +0 -33
  60. data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +0 -23
  61. data/lib/skylight/normalizers/moped/query.rb +0 -100
  62. data/lib/skylight/probes.rb +0 -129
  63. data/lib/skylight/probes/action_controller.rb +0 -64
  64. data/lib/skylight/probes/action_dispatch.rb +0 -30
  65. data/lib/skylight/probes/action_view.rb +0 -43
  66. data/lib/skylight/probes/active_model_serializers.rb +0 -55
  67. data/lib/skylight/probes/elasticsearch.rb +0 -37
  68. data/lib/skylight/probes/excon.rb +0 -26
  69. data/lib/skylight/probes/excon/middleware.rb +0 -68
  70. data/lib/skylight/probes/faraday.rb +0 -22
  71. data/lib/skylight/probes/grape.rb +0 -88
  72. data/lib/skylight/probes/httpclient.rb +0 -46
  73. data/lib/skylight/probes/middleware.rb +0 -68
  74. data/lib/skylight/probes/mongo.rb +0 -161
  75. data/lib/skylight/probes/mongoid.rb +0 -21
  76. data/lib/skylight/probes/moped.rb +0 -39
  77. data/lib/skylight/probes/net_http.rb +0 -58
  78. data/lib/skylight/probes/redis.rb +0 -71
  79. data/lib/skylight/probes/sequel.rb +0 -37
  80. data/lib/skylight/probes/sinatra.rb +0 -76
  81. data/lib/skylight/probes/tilt.rb +0 -31
  82. data/lib/skylight/subscriber.rb +0 -122
  83. data/lib/skylight/user_config.rb +0 -60
  84. data/lib/skylight/util.rb +0 -17
  85. data/lib/skylight/util/allocation_free.rb +0 -26
  86. data/lib/skylight/util/clock.rb +0 -54
  87. data/lib/skylight/util/deploy.rb +0 -132
  88. data/lib/skylight/util/gzip.rb +0 -21
  89. data/lib/skylight/util/inflector.rb +0 -112
  90. data/lib/skylight/util/logging.rb +0 -127
  91. data/lib/skylight/util/multi_io.rb +0 -21
  92. data/lib/skylight/util/native_ext_fetcher.rb +0 -253
  93. data/lib/skylight/util/platform.rb +0 -75
  94. data/lib/skylight/util/proxy.rb +0 -13
  95. data/lib/skylight/vendor/active_support/notifications.rb +0 -207
  96. data/lib/skylight/vendor/active_support/notifications/fanout.rb +0 -159
  97. data/lib/skylight/vendor/active_support/notifications/instrumenter.rb +0 -72
  98. data/lib/skylight/vendor/active_support/per_thread_registry.rb +0 -52
  99. data/lib/skylight/vendor/thread_safe.rb +0 -126
  100. data/lib/skylight/vendor/thread_safe/non_concurrent_cache_backend.rb +0 -133
  101. data/lib/skylight/vendor/thread_safe/synchronized_cache_backend.rb +0 -76
  102. data/lib/skylight/vm/gc.rb +0 -70
@@ -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
- # @api private
7
- class Instrumenter
8
- KEY = :__skylight_current_trace
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 current_trace=(trace)
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
- def shutdown
126
- @subscriber.unregister!
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
- cat = "other.#{cat}" unless match?(cat, TIER_REGEX)
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 limited_description(description)
222
- endpoint = @trace_info.current.endpoint
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
@@ -1,92 +1,4 @@
1
1
  module Skylight
2
- # @api private
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
@@ -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
- unless Skylight.native?
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