skylight 3.1.5 → 4.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,22 +1,22 @@
1
- require 'skylight/core/util/platform'
1
+ require "skylight/core/util/platform"
2
2
 
3
3
  module Skylight
4
4
  # @api private
5
5
  # Whether or not the native extension is present
6
- @@has_native_ext = false
6
+ @has_native_ext = false
7
7
 
8
8
  def self.native?
9
- @@has_native_ext
9
+ @has_native_ext
10
10
  end
11
11
 
12
12
  def self.libskylight_path
13
- ENV['SKYLIGHT_LIB_PATH'] || File.expand_path("../native/#{Core::Util::Platform.tuple}", __FILE__)
13
+ ENV["SKYLIGHT_LIB_PATH"] || File.expand_path("../native/#{Core::Util::Platform.tuple}", __FILE__)
14
14
  end
15
15
 
16
- skylight_required = ENV.key?("SKYLIGHT_REQUIRED") && ENV['SKYLIGHT_REQUIRED'] !~ /^false$/i
16
+ skylight_required = ENV.key?("SKYLIGHT_REQUIRED") && ENV["SKYLIGHT_REQUIRED"] !~ /^false$/i
17
17
 
18
18
  begin
19
- unless ENV.key?("SKYLIGHT_DISABLE_AGENT") && ENV['SKYLIGHT_DISABLE_AGENT'] !~ /^false$/i
19
+ unless ENV.key?("SKYLIGHT_DISABLE_AGENT") && ENV["SKYLIGHT_DISABLE_AGENT"] !~ /^false$/i
20
20
  lib = "#{libskylight_path}/libskylight.#{Core::Util::Platform.libext}"
21
21
 
22
22
  if File.exist?(lib)
@@ -27,7 +27,7 @@ module Skylight
27
27
  load_libskylight(lib)
28
28
 
29
29
  # If nothing was thrown, then the native extension is present
30
- @@has_native_ext = true
30
+ @has_native_ext = true
31
31
  elsif skylight_required
32
32
  raise LoadError, "Cannot find native extensions in #{libskylight_path}"
33
33
  end
@@ -35,7 +35,7 @@ module Skylight
35
35
  rescue RuntimeError => e
36
36
  # Old versions of OS X can have dlerrors, just treat it like a missing native
37
37
  raise if skylight_required || e.message !~ /dlerror/
38
- rescue LoadError => e
38
+ rescue LoadError
39
39
  raise if skylight_required
40
40
  end
41
41
 
@@ -43,7 +43,7 @@ module Skylight
43
43
  Skylight::Core::Util::Clock.use_native!
44
44
  else
45
45
  class Instrumenter
46
- def self.native_new(*args)
46
+ def self.native_new(*_args)
47
47
  allocate
48
48
  end
49
49
  end
@@ -52,13 +52,13 @@ module Skylight
52
52
  # @api private
53
53
  def self.check_install_errors(config)
54
54
  # Note: An unsupported arch doesn't count as an error.
55
- install_log = File.expand_path("../../../ext/install.log", __FILE__)
55
+ install_log = File.expand_path("../../ext/install.log", __dir__)
56
56
 
57
57
  if File.exist?(install_log) && File.read(install_log) =~ /ERROR/
58
58
  config.alert_logger.error \
59
- "[SKYLIGHT] [#{Skylight::VERSION}] The Skylight native extension failed to install. " \
60
- "Please check #{install_log} and notify support@skylight.io. " \
61
- "The missing extension will not affect the functioning of your application."
59
+ "[SKYLIGHT] [#{Skylight::VERSION}] The Skylight native extension failed to install. " \
60
+ "Please check #{install_log} and notify support@skylight.io. " \
61
+ "The missing extension will not affect the functioning of your application."
62
62
  end
63
63
  end
64
64
 
@@ -1,17 +1,17 @@
1
- require 'uri'
2
- require 'logger'
3
- require 'net/http'
4
- require 'fileutils'
5
- require 'digest/sha2'
6
- require 'open3'
7
- require 'skylight/util/ssl'
8
- require 'skylight/core/util/proxy'
1
+ require "uri"
2
+ require "logger"
3
+ require "net/http"
4
+ require "fileutils"
5
+ require "digest/sha2"
6
+ require "open3"
7
+ require "skylight/util/ssl"
8
+ require "skylight/core/util/proxy"
9
9
 
10
10
  # Used from extconf.rb
11
11
  module Skylight
12
12
  # Utility class for fetching the native extension from a URL
13
13
  class NativeExtFetcher
14
- BASE_URL = "https://s3.amazonaws.com/skylight-agent-packages/skylight-native"
14
+ BASE_URL = "https://s3.amazonaws.com/skylight-agent-packages/skylight-native".freeze
15
15
  MAX_REDIRECTS = 5
16
16
  MAX_RETRIES = 3
17
17
 
@@ -21,18 +21,10 @@ module Skylight
21
21
 
22
22
  # Creates a new fetcher and fetches
23
23
  # @param opts [Hash]
24
- def self.fetch(opts = {})
25
- fetcher = new(
26
- opts[:source] || BASE_URL,
27
- opts[:target],
28
- opts[:version],
29
- opts[:checksum],
30
- opts[:arch],
31
- opts[:required],
32
- opts[:platform],
33
- opts[:logger] || Logger.new(STDOUT))
34
-
35
- fetcher.fetch
24
+ def self.fetch(**args)
25
+ args[:source] ||= BASE_URL
26
+ args[:logger] ||= Logger.new(STDOUT)
27
+ new(**args).fetch
36
28
  end
37
29
 
38
30
  # @param source [String] the base url to download from
@@ -43,7 +35,7 @@ module Skylight
43
35
  # @param required [Boolean] whether the download is required to be successful
44
36
  # @param platform
45
37
  # @param log [Logger]
46
- def initialize(source, target, version, checksum, arch, required, platform, log)
38
+ def initialize(source:, target:, version:, checksum:, arch:, required: false, platform: nil, logger:)
47
39
  raise "source required" unless source
48
40
  raise "target required" unless target
49
41
  raise "checksum required" unless checksum
@@ -56,7 +48,7 @@ module Skylight
56
48
  @required = required
57
49
  @platform = platform
58
50
  @arch = arch
59
- @log = log
51
+ @logger = logger
60
52
  end
61
53
 
62
54
  # Fetch the native extension, verify, inflate, and save (if applicable)
@@ -68,7 +60,7 @@ module Skylight
68
60
 
69
61
  tar_gz = "#{@target}/#{basename}"
70
62
 
71
- unless sha2 = fetch_native_ext(source_uri, tar_gz, MAX_RETRIES, MAX_REDIRECTS)
63
+ unless (sha2 = fetch_native_ext(source_uri, tar_gz, MAX_RETRIES, MAX_REDIRECTS))
72
64
  maybe_raise "could not fetch native extension"
73
65
  return
74
66
  end
@@ -91,7 +83,7 @@ module Skylight
91
83
  end
92
84
 
93
85
  def fetch_native_ext(uri, out, attempts, redirects)
94
- redirects.times do |i|
86
+ redirects.times do
95
87
  # Ensure the location is available
96
88
  mkdir_p File.dirname(out)
97
89
  rm_f out
@@ -103,7 +95,7 @@ module Skylight
103
95
  begin
104
96
  host, port, use_ssl, path = deconstruct_uri(uri)
105
97
 
106
- File.open out, 'w' do |f|
98
+ File.open out, "w" do |f|
107
99
  res, extra = http_get(host, port, use_ssl, path, f)
108
100
 
109
101
  case res
@@ -132,7 +124,7 @@ module Skylight
132
124
  end
133
125
 
134
126
  log "exceeded max redirects"
135
- return
127
+ nil
136
128
  end
137
129
 
138
130
  # Get with `Net::HTTP`
@@ -145,10 +137,11 @@ module Skylight
145
137
  #
146
138
  # If `ENV['HTTP_PROXY']` is set, it will be used as a proxy for this request.
147
139
  def http_get(host, port, use_ssl, path, out)
148
- if http_proxy = Core::Util::Proxy.detect_url(ENV)
140
+ if (http_proxy = Core::Util::Proxy.detect_url(ENV))
149
141
  log "connecting with proxy: #{http_proxy}"
150
142
  uri = URI.parse(http_proxy)
151
- p_host, p_port = uri.host, uri.port
143
+ p_host = uri.host
144
+ p_port = uri.port
152
145
  p_user, p_pass = uri.userinfo.split(/:/) if uri.userinfo
153
146
  end
154
147
 
@@ -170,13 +163,13 @@ module Skylight
170
163
  out.write chunk
171
164
  end
172
165
 
173
- return [ :success, digest.hexdigest ]
166
+ return [:success, digest.hexdigest]
174
167
  when Net::HTTPRedirection
175
- unless location = resp['location']
168
+ unless (location = resp["location"])
176
169
  raise "received redirect but no location"
177
170
  end
178
171
 
179
- return [ :redirect, location ]
172
+ return [:redirect, location]
180
173
  else
181
174
  raise "received HTTP status code #{resp.code}"
182
175
  end
@@ -217,7 +210,7 @@ module Skylight
217
210
  # @return [Array<String>] the host, port, scheme, and request_uri
218
211
  def deconstruct_uri(uri)
219
212
  uri = URI(uri)
220
- [ uri.host, uri.port, uri.scheme == 'https', uri.request_uri ]
213
+ [uri.host, uri.port, uri.scheme == "https", uri.request_uri]
221
214
  end
222
215
 
223
216
  # Log an error and raise if `required` is `true`
@@ -238,7 +231,7 @@ module Skylight
238
231
  # @return [void]
239
232
  def log(msg)
240
233
  msg = "[SKYLIGHT] #{msg}"
241
- @log.info msg
234
+ @logger.info msg
242
235
  end
243
236
 
244
237
  # Log an `error` to the `logger`
@@ -246,10 +239,10 @@ module Skylight
246
239
  # @param msg [String]
247
240
  # @param e [Exception] the exception associated with the error
248
241
  # @return [void]
249
- def error(msg, e=nil)
242
+ def error(msg, err = nil)
250
243
  msg = "[SKYLIGHT] #{msg}"
251
- msg << "\n#{e.backtrace.join("\n")}" if e
252
- @log.error msg
244
+ msg << "\n#{err.backtrace.join("\n")}" if err
245
+ @logger.error msg
253
246
  end
254
247
  end
255
248
  end
@@ -4,10 +4,10 @@ module Skylight
4
4
  class Probe
5
5
  def install
6
6
  class << ::Sinatra::Base
7
- alias build_without_sk build
7
+ alias_method :build_without_sk, :build
8
8
 
9
9
  def build(*args, &block)
10
- self.use Skylight::Middleware
10
+ use Skylight::Middleware
11
11
  build_without_sk(*args, &block)
12
12
  end
13
13
  end
@@ -1,16 +1,18 @@
1
- require 'skylight/core/railtie'
1
+ require "skylight/core/railtie"
2
2
 
3
3
  module Skylight
4
4
  class Railtie < Rails::Railtie
5
5
  include Skylight::Core::Railtie
6
6
 
7
+ # rubocop:disable Style/SingleLineMethods, Layout/EmptyLineBetweenDefs
7
8
  def self.config_class; Skylight::Config end
8
9
  def self.middleware_class; Skylight::Middleware end
10
+ # rubocop:enable Style/SingleLineMethods, Layout/EmptyLineBetweenDefs
9
11
 
10
12
  config.skylight = ActiveSupport::OrderedOptions.new
11
13
 
12
14
  # The environments in which skylight should be enabled
13
- config.skylight.environments = ['production']
15
+ config.skylight.environments = ["production"]
14
16
 
15
17
  # The path to the configuration file
16
18
  config.skylight.config_path = "config/skylight.yml"
@@ -19,29 +21,51 @@ module Skylight
19
21
  # net_http, action_controller, action_dispatch, action_view, and middleware are on by default
20
22
  # See https://www.skylight.io/support/getting-more-from-skylight#available-instrumentation-options
21
23
  # for a full list.
22
- config.skylight.probes = ['net_http', 'action_controller', 'action_dispatch', 'action_view', 'middleware', 'active_job_enqueue']
24
+ config.skylight.probes = %w[net_http action_controller action_dispatch action_view middleware active_job_enqueue]
23
25
 
24
26
  # The position in the middleware stack to place Skylight
25
27
  # Default is first, but can be `{ after: Middleware::Name }` or `{ before: Middleware::Name }`
26
28
  config.skylight.middleware_position = 0
27
29
 
28
- initializer 'skylight.configure' do |app|
30
+ initializer "skylight.configure" do |app|
29
31
  run_initializer(app)
30
32
  end
31
33
 
32
34
  private
33
35
 
36
+ def activate?(sk_config)
37
+ return false unless super && sk_config
38
+ activate_for_worker?(sk_config) || activate_for_web?(sk_config)
39
+ end
40
+
41
+ # We must have an opt-in signal
42
+ def activate_for_worker?(sk_config)
43
+ return unless sk_config.worker_context?
44
+
45
+ reasons = []
46
+ reasons << "the 'active_job' probe is enabled" if sk_rails_config.probes.include?("active_job")
47
+ reasons << "SKYLIGHT_ENABLE_SIDEKIQ is set" if sk_config.enable_sidekiq?
48
+
49
+ return if reasons.empty?
50
+
51
+ sk_config.logger.warn("Activating Skylight for Background Jobs (alpha) because #{reasons.to_sentence}")
52
+ true
53
+ end
54
+
55
+ def activate_for_web?(sk_config)
56
+ sk_config.web_context?
57
+ end
58
+
34
59
  def development_warning
35
60
  super + "\n(To disable this message for all local apps, run `skylight disable_dev_warning`.)"
36
61
  end
37
62
 
38
63
  def load_skylight_config(app)
39
- super.tap do |config|
40
- if config[:report_rails_env]
41
- config[:env] ||= Rails.env.to_s
64
+ super.tap do |sk_config|
65
+ if sk_config && sk_config[:report_rails_env]
66
+ sk_config[:env] ||= Rails.env.to_s
42
67
  end
43
68
  end
44
69
  end
45
-
46
70
  end
47
71
  end
@@ -1,2 +1,2 @@
1
- require 'skylight'
1
+ require "skylight"
2
2
  Skylight.probe(:sinatra_add_middleware, :sinatra, :tilt, :sequel)
@@ -23,8 +23,8 @@ module Skylight
23
23
  !!@too_many_spans
24
24
  end
25
25
 
26
- def maybe_broken(e)
27
- if e.is_a?(Skylight::MaximumTraceSpansError) && config.get(:report_max_spans_exceeded)
26
+ def maybe_broken(error)
27
+ if error.is_a?(Skylight::MaximumTraceSpansError) && config.get(:report_max_spans_exceeded)
28
28
  too_many_spans!
29
29
  else
30
30
  super
@@ -33,8 +33,8 @@ module Skylight
33
33
 
34
34
  def traced
35
35
  if too_many_spans?
36
- error("[E%04d] The request exceeded the maximum number of spans allowed. It will still " \
37
- "be tracked but with reduced information. endpoint=%s", Skylight::MaximumTraceSpansError.code, endpoint)
36
+ error("[E%04d] The request exceeded the maximum number of spans allowed. It will still " \
37
+ "be tracked but with reduced information. endpoint=%s", Skylight::MaximumTraceSpansError.code, endpoint)
38
38
  end
39
39
 
40
40
  super
@@ -51,6 +51,5 @@ module Skylight
51
51
  def use_pruning?
52
52
  config.get(:prune_large_traces)
53
53
  end
54
-
55
54
  end
56
55
  end
@@ -1,33 +1,98 @@
1
1
  module Skylight
2
2
  module Util
3
3
  class Component
4
-
5
4
  attr_accessor :environment, :name
6
5
 
7
6
  NAME_FORMAT = /\A[a-z0-9-]+\z/
8
- DEFAULT_NAME = 'web'.freeze
9
- DEFAULT_ENVIRONMENT = 'production'.freeze
7
+ DEFAULT_NAME = "web".freeze
8
+ WORKER_NAME = "worker".freeze
9
+ DEFAULT_ENVIRONMENT = "production".freeze
10
+
11
+ WORKER_PROGRAM_MATCHER = Regexp.union [
12
+ /sidekiq$/i,
13
+ /backburner$/i,
14
+ /delayed_job$/i,
15
+ /que$/i,
16
+ /sneakers$/i
17
+ ]
18
+
19
+ WORKER_RAKE_MATCHER = Regexp.union [
20
+ /\Aresque:/,
21
+ /\Abackburner:/,
22
+ /\Ajobs:/, # DelayedJob. can also be `rake jobs:workoff`
23
+ /\Aqu:/,
24
+ /\Aque:/,
25
+ /\Aqc:/,
26
+ /\Asneakers:/
27
+ ]
10
28
 
11
29
  def initialize(environment, name)
12
30
  @environment = environment || DEFAULT_ENVIRONMENT
13
- @name = name || DEFAULT_NAME
31
+ @name = resolve_name(name)
14
32
 
15
33
  raise ArgumentError, "environment can't be blank" if @environment.empty?
16
- validate_string!(@environment, 'environment')
17
- validate_string!(@name, 'name')
34
+ validate_string!(@environment, "environment")
35
+ validate_string!(@name, "name")
18
36
  end
19
37
 
20
38
  def to_s
21
39
  "#{name}:#{environment}"
22
40
  end
23
41
 
24
- private
42
+ def web?
43
+ name == DEFAULT_NAME
44
+ end
25
45
 
26
- def validate_string!(string, kind)
27
- return true if string =~ NAME_FORMAT
28
- raise ArgumentError, "#{kind} can only contain lowercase letters, numbers, and dashes"
46
+ def worker?
47
+ !web?
29
48
  end
49
+
50
+ # keys here should match those from the main config
51
+ def as_json(*)
52
+ {
53
+ component: name,
54
+ env: environment
55
+ }
56
+ end
57
+
58
+ private
59
+
60
+ def program_name
61
+ $PROGRAM_NAME
62
+ end
63
+
64
+ def argv
65
+ ARGV
66
+ end
67
+
68
+ def resolve_name(given_name)
69
+ return DEFAULT_NAME if known_web_context?
70
+ return given_name if given_name
71
+ return WORKER_NAME if known_worker_context?
72
+ DEFAULT_NAME
73
+ end
74
+
75
+ def validate_string!(string, kind)
76
+ return true if string =~ NAME_FORMAT
77
+ raise ArgumentError, "#{kind} can only contain lowercase letters, numbers, and dashes"
78
+ end
79
+
80
+ def known_web_context?
81
+ rails_server? || rackup?
82
+ end
83
+
84
+ def known_worker_context?
85
+ return true if program_name =~ WORKER_PROGRAM_MATCHER
86
+ program_name[/rake$/] && argv.any? { |arg| arg =~ WORKER_RAKE_MATCHER }
87
+ end
88
+
89
+ def rails_server?
90
+ defined?(Rails::Server)
91
+ end
92
+
93
+ def rackup?
94
+ program_name[/rackup$/]
95
+ end
30
96
  end
31
97
  end
32
98
  end
33
-