skylight 3.1.5 → 4.0.0.alpha

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.
@@ -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
-