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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -9
- data/bin/skylight +1 -1
- data/ext/extconf.rb +74 -76
- data/ext/libskylight.yml +7 -6
- data/lib/skylight.rb +15 -13
- data/lib/skylight/api.rb +40 -37
- data/lib/skylight/cli.rb +55 -60
- data/lib/skylight/cli/doctor.rb +13 -14
- data/lib/skylight/cli/helpers.rb +20 -22
- data/lib/skylight/cli/merger.rb +119 -116
- data/lib/skylight/config.rb +110 -96
- data/lib/skylight/errors.rb +8 -10
- data/lib/skylight/helpers.rb +35 -37
- data/lib/skylight/native.rb +13 -13
- data/lib/skylight/native_ext_fetcher.rb +30 -37
- data/lib/skylight/probes/sinatra_add_middleware.rb +2 -2
- data/lib/skylight/railtie.rb +32 -8
- data/lib/skylight/sinatra.rb +1 -1
- data/lib/skylight/trace.rb +4 -5
- data/lib/skylight/util/component.rb +76 -11
- data/lib/skylight/util/deploy.rb +10 -21
- data/lib/skylight/util/hostname.rb +4 -4
- data/lib/skylight/util/http.rb +134 -136
- data/lib/skylight/util/ssl.rb +6 -6
- data/lib/skylight/version.rb +1 -1
- metadata +51 -50
data/lib/skylight/native.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
require
|
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
|
-
|
6
|
+
@has_native_ext = false
|
7
7
|
|
8
8
|
def self.native?
|
9
|
-
|
9
|
+
@has_native_ext
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.libskylight_path
|
13
|
-
ENV[
|
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[
|
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[
|
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
|
-
|
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
|
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(*
|
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("
|
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
|
-
|
60
|
-
|
61
|
-
|
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
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
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(
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
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
|
-
@
|
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
|
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,
|
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
|
-
|
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
|
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 [
|
166
|
+
return [:success, digest.hexdigest]
|
174
167
|
when Net::HTTPRedirection
|
175
|
-
unless location = resp[
|
168
|
+
unless (location = resp["location"])
|
176
169
|
raise "received redirect but no location"
|
177
170
|
end
|
178
171
|
|
179
|
-
return [
|
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
|
-
[
|
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
|
-
@
|
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,
|
242
|
+
def error(msg, err = nil)
|
250
243
|
msg = "[SKYLIGHT] #{msg}"
|
251
|
-
msg << "\n#{
|
252
|
-
@
|
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
|
-
|
7
|
+
alias_method :build_without_sk, :build
|
8
8
|
|
9
9
|
def build(*args, &block)
|
10
|
-
|
10
|
+
use Skylight::Middleware
|
11
11
|
build_without_sk(*args, &block)
|
12
12
|
end
|
13
13
|
end
|
data/lib/skylight/railtie.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
-
require
|
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 = [
|
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 = [
|
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
|
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 |
|
40
|
-
if
|
41
|
-
|
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
|
data/lib/skylight/sinatra.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
require
|
1
|
+
require "skylight"
|
2
2
|
Skylight.probe(:sinatra_add_middleware, :sinatra, :tilt, :sequel)
|
data/lib/skylight/trace.rb
CHANGED
@@ -23,8 +23,8 @@ module Skylight
|
|
23
23
|
!!@too_many_spans
|
24
24
|
end
|
25
25
|
|
26
|
-
def maybe_broken(
|
27
|
-
if
|
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
|
-
|
37
|
-
|
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 =
|
9
|
-
|
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
|
31
|
+
@name = resolve_name(name)
|
14
32
|
|
15
33
|
raise ArgumentError, "environment can't be blank" if @environment.empty?
|
16
|
-
validate_string!(@environment,
|
17
|
-
validate_string!(@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
|
-
|
42
|
+
def web?
|
43
|
+
name == DEFAULT_NAME
|
44
|
+
end
|
25
45
|
|
26
|
-
def
|
27
|
-
|
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
|
-
|