skylight 5.0.1 → 5.1.1
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 +395 -364
- data/CLA.md +1 -1
- data/LICENSE.md +7 -17
- data/README.md +1 -1
- data/ext/extconf.rb +42 -54
- data/ext/libskylight.yml +9 -6
- data/lib/skylight.rb +20 -30
- data/lib/skylight/api.rb +22 -18
- data/lib/skylight/cli.rb +47 -46
- data/lib/skylight/cli/doctor.rb +50 -50
- data/lib/skylight/cli/helpers.rb +19 -19
- data/lib/skylight/cli/merger.rb +141 -139
- data/lib/skylight/config.rb +265 -300
- data/lib/skylight/deprecation.rb +4 -4
- data/lib/skylight/errors.rb +3 -4
- data/lib/skylight/extensions.rb +17 -29
- data/lib/skylight/extensions/source_location.rb +128 -128
- data/lib/skylight/formatters/http.rb +1 -3
- data/lib/skylight/gc.rb +30 -40
- data/lib/skylight/helpers.rb +43 -41
- data/lib/skylight/instrumenter.rb +25 -18
- data/lib/skylight/middleware.rb +31 -35
- data/lib/skylight/native.rb +8 -10
- data/lib/skylight/native_ext_fetcher.rb +10 -12
- data/lib/skylight/normalizers.rb +43 -39
- data/lib/skylight/normalizers/action_controller/process_action.rb +24 -25
- data/lib/skylight/normalizers/action_controller/send_file.rb +7 -6
- data/lib/skylight/normalizers/action_dispatch/route_set.rb +7 -7
- data/lib/skylight/normalizers/active_job/perform.rb +48 -44
- data/lib/skylight/normalizers/active_model_serializers/render.rb +7 -3
- data/lib/skylight/normalizers/active_storage.rb +11 -13
- data/lib/skylight/normalizers/active_support/cache.rb +1 -12
- data/lib/skylight/normalizers/coach/handler_finish.rb +1 -3
- data/lib/skylight/normalizers/default.rb +1 -9
- data/lib/skylight/normalizers/faraday/request.rb +1 -3
- data/lib/skylight/normalizers/grape/endpoint.rb +13 -19
- data/lib/skylight/normalizers/grape/endpoint_run.rb +16 -18
- data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +1 -3
- data/lib/skylight/normalizers/graphql/base.rb +23 -28
- data/lib/skylight/normalizers/render.rb +19 -21
- data/lib/skylight/normalizers/shrine.rb +15 -17
- data/lib/skylight/normalizers/sql.rb +4 -4
- data/lib/skylight/probes.rb +38 -46
- data/lib/skylight/probes/action_controller.rb +32 -28
- data/lib/skylight/probes/action_dispatch/request_id.rb +9 -5
- data/lib/skylight/probes/action_dispatch/routing/route_set.rb +7 -5
- data/lib/skylight/probes/action_view.rb +9 -10
- data/lib/skylight/probes/active_job_enqueue.rb +3 -9
- data/lib/skylight/probes/active_model_serializers.rb +8 -8
- data/lib/skylight/probes/delayed_job.rb +37 -42
- data/lib/skylight/probes/elasticsearch.rb +3 -5
- data/lib/skylight/probes/excon.rb +1 -1
- data/lib/skylight/probes/excon/middleware.rb +22 -23
- data/lib/skylight/probes/graphql.rb +2 -7
- data/lib/skylight/probes/middleware.rb +14 -5
- data/lib/skylight/probes/mongo.rb +83 -91
- data/lib/skylight/probes/net_http.rb +1 -1
- data/lib/skylight/probes/redis.rb +5 -17
- data/lib/skylight/probes/sequel.rb +7 -11
- data/lib/skylight/probes/sinatra.rb +8 -5
- data/lib/skylight/probes/tilt.rb +2 -4
- data/lib/skylight/railtie.rb +121 -135
- data/lib/skylight/sidekiq.rb +4 -5
- data/lib/skylight/subscriber.rb +31 -33
- data/lib/skylight/test.rb +89 -84
- data/lib/skylight/trace.rb +121 -115
- data/lib/skylight/user_config.rb +14 -17
- data/lib/skylight/util/clock.rb +1 -0
- data/lib/skylight/util/component.rb +18 -21
- data/lib/skylight/util/deploy.rb +11 -13
- data/lib/skylight/util/http.rb +104 -105
- data/lib/skylight/util/logging.rb +4 -6
- data/lib/skylight/util/lru_cache.rb +2 -6
- data/lib/skylight/util/platform.rb +2 -6
- data/lib/skylight/util/ssl.rb +1 -25
- data/lib/skylight/version.rb +1 -1
- data/lib/skylight/vm/gc.rb +1 -9
- metadata +6 -6
data/lib/skylight/user_config.rb
CHANGED
@@ -14,16 +14,18 @@ module Skylight
|
|
14
14
|
def file_path
|
15
15
|
return @file_path if @file_path
|
16
16
|
|
17
|
-
config_path =
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
17
|
+
config_path =
|
18
|
+
@config[:user_config_path] ||
|
19
|
+
begin
|
20
|
+
require "etc"
|
21
|
+
home_dir = ENV["HOME"] || Etc.getpwuid.dir || (ENV["USER"] && File.expand_path("~#{ENV["USER"]}"))
|
22
|
+
if home_dir
|
23
|
+
File.join(home_dir, ".skylight")
|
24
|
+
else
|
25
|
+
raise ConfigError,
|
26
|
+
"The Skylight `user_config_path` must be defined since the home directory cannot be inferred"
|
27
|
+
end
|
28
|
+
end
|
27
29
|
|
28
30
|
@file_path = File.expand_path(config_path)
|
29
31
|
end
|
@@ -46,16 +48,11 @@ module Skylight
|
|
46
48
|
|
47
49
|
def save
|
48
50
|
FileUtils.mkdir_p(File.dirname(file_path))
|
49
|
-
File.open(file_path, "w")
|
50
|
-
f.puts YAML.dump(to_hash)
|
51
|
-
end
|
51
|
+
File.open(file_path, "w") { |f| f.puts YAML.dump(to_hash) }
|
52
52
|
end
|
53
53
|
|
54
54
|
def to_hash
|
55
|
-
{
|
56
|
-
"disable_dev_warning" => disable_dev_warning,
|
57
|
-
"disable_env_warning" => disable_env_warning
|
58
|
-
}
|
55
|
+
{ "disable_dev_warning" => disable_dev_warning, "disable_env_warning" => disable_env_warning }
|
59
56
|
end
|
60
57
|
end
|
61
58
|
end
|
data/lib/skylight/util/clock.rb
CHANGED
@@ -14,7 +14,7 @@ module Skylight
|
|
14
14
|
|
15
15
|
def initialize(environment, name, force_worker: false)
|
16
16
|
@environment = environment || DEFAULT_ENVIRONMENT
|
17
|
-
@name
|
17
|
+
@name = resolve_name(name, force_worker)
|
18
18
|
|
19
19
|
raise ArgumentError, "environment can't be blank" if @environment.empty?
|
20
20
|
|
@@ -40,35 +40,32 @@ module Skylight
|
|
40
40
|
|
41
41
|
# keys here should match those from the main config
|
42
42
|
def as_json(*)
|
43
|
-
{
|
44
|
-
component: name,
|
45
|
-
env: environment
|
46
|
-
}
|
43
|
+
{ component: name, env: environment }
|
47
44
|
end
|
48
45
|
|
49
46
|
private
|
50
47
|
|
51
|
-
|
52
|
-
|
53
|
-
|
48
|
+
def program_name
|
49
|
+
$PROGRAM_NAME
|
50
|
+
end
|
54
51
|
|
55
|
-
|
56
|
-
|
57
|
-
|
52
|
+
def argv
|
53
|
+
ARGV
|
54
|
+
end
|
58
55
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
56
|
+
def resolve_name(given_name, force_worker)
|
57
|
+
# don't allow workers to be called 'web'
|
58
|
+
return WORKER_NAME if force_worker && (given_name.nil? || given_name == DEFAULT_NAME)
|
59
|
+
return DEFAULT_NAME if given_name.nil?
|
63
60
|
|
64
|
-
|
65
|
-
|
61
|
+
given_name
|
62
|
+
end
|
66
63
|
|
67
|
-
|
68
|
-
|
64
|
+
def validate_string!(string, kind)
|
65
|
+
return true if string =~ NAME_FORMAT
|
69
66
|
|
70
|
-
|
71
|
-
|
67
|
+
raise ArgumentError, "#{kind} can only contain lowercase letters, numbers, and dashes"
|
68
|
+
end
|
72
69
|
end
|
73
70
|
end
|
74
71
|
end
|
data/lib/skylight/util/deploy.rb
CHANGED
@@ -48,9 +48,7 @@ module Skylight
|
|
48
48
|
|
49
49
|
def initialize(*)
|
50
50
|
super
|
51
|
-
if description && !id
|
52
|
-
warn "The configured deploy will be ignored as an id or git_sha must be provided."
|
53
|
-
end
|
51
|
+
warn "The configured deploy will be ignored as an id or git_sha must be provided." if description && !id
|
54
52
|
end
|
55
53
|
|
56
54
|
def id
|
@@ -86,13 +84,13 @@ module Skylight
|
|
86
84
|
|
87
85
|
private
|
88
86
|
|
89
|
-
|
90
|
-
|
87
|
+
def get_info
|
88
|
+
info_path = config[:'heroku.dyno_info_path']
|
91
89
|
|
92
|
-
|
93
|
-
|
94
|
-
end
|
90
|
+
if File.exist?(info_path) && (info = JSON.parse(File.read(info_path)))
|
91
|
+
info["release"]
|
95
92
|
end
|
93
|
+
end
|
96
94
|
end
|
97
95
|
|
98
96
|
class GitDeploy < EmptyDeploy
|
@@ -105,12 +103,12 @@ module Skylight
|
|
105
103
|
|
106
104
|
private
|
107
105
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
end
|
106
|
+
def get_info
|
107
|
+
Dir.chdir(config.root) do
|
108
|
+
info = `git log -1 --pretty="%H %s" 2>&1`
|
109
|
+
info.split(" ", 2).map(&:strip) if $CHILD_STATUS.success?
|
113
110
|
end
|
111
|
+
end
|
114
112
|
end
|
115
113
|
|
116
114
|
DEPLOY_TYPES = [DefaultDeploy, HerokuDeploy, GitDeploy].freeze
|
data/lib/skylight/util/http.rb
CHANGED
@@ -10,14 +10,14 @@ module Skylight
|
|
10
10
|
module Util
|
11
11
|
class HTTP
|
12
12
|
CONTENT_ENCODING = "content-encoding".freeze
|
13
|
-
CONTENT_LENGTH
|
14
|
-
CONTENT_TYPE
|
15
|
-
ACCEPT
|
16
|
-
X_VERSION_HDR
|
13
|
+
CONTENT_LENGTH = "content-length".freeze
|
14
|
+
CONTENT_TYPE = "content-type".freeze
|
15
|
+
ACCEPT = "Accept".freeze
|
16
|
+
X_VERSION_HDR = "x-skylight-agent-version".freeze
|
17
17
|
APPLICATION_JSON = "application/json".freeze
|
18
|
-
AUTHORIZATION
|
19
|
-
DEFLATE
|
20
|
-
GZIP
|
18
|
+
AUTHORIZATION = "authorization".freeze
|
19
|
+
DEFLATE = "deflate".freeze
|
20
|
+
GZIP = "gzip".freeze
|
21
21
|
|
22
22
|
include Logging
|
23
23
|
|
@@ -35,7 +35,8 @@ module Skylight
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
class ReadResponseError < StandardError
|
38
|
+
class ReadResponseError < StandardError
|
39
|
+
end
|
39
40
|
|
40
41
|
def initialize(config, service = :auth, opts = {})
|
41
42
|
@config = config
|
@@ -46,7 +47,7 @@ module Skylight
|
|
46
47
|
|
47
48
|
url = URI.parse(url)
|
48
49
|
|
49
|
-
@ssl
|
50
|
+
@ssl = url.scheme == "https"
|
50
51
|
@host = url.host
|
51
52
|
@port = url.port
|
52
53
|
|
@@ -81,131 +82,129 @@ module Skylight
|
|
81
82
|
|
82
83
|
private
|
83
84
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
end
|
85
|
+
def get_timeout(type, config, service, opts)
|
86
|
+
config.duration_ms("#{service}_http_#{type}_timeout") || opts[:timeout] || 15
|
87
|
+
end
|
88
88
|
|
89
|
-
|
90
|
-
|
89
|
+
def build_request(type, endpoint, hdrs, length = nil)
|
90
|
+
headers = {}
|
91
91
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
92
|
+
headers[CONTENT_LENGTH] = length.to_s if length
|
93
|
+
headers[AUTHORIZATION] = authentication if authentication
|
94
|
+
headers[ACCEPT] = APPLICATION_JSON
|
95
|
+
headers[X_VERSION_HDR] = VERSION
|
96
|
+
headers[CONTENT_ENCODING] = GZIP if length && @deflate
|
97
97
|
|
98
|
-
|
99
|
-
headers[k] = v
|
100
|
-
end
|
98
|
+
hdrs.each { |k, v| headers[k] = v }
|
101
99
|
|
102
|
-
|
100
|
+
type.new(endpoint, headers)
|
101
|
+
end
|
102
|
+
|
103
|
+
def do_request(http, req)
|
104
|
+
begin
|
105
|
+
client = http.start
|
106
|
+
rescue StandardError => e
|
107
|
+
# TODO: Retry here
|
108
|
+
raise StartError, e
|
103
109
|
end
|
104
110
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
raise StartError, e
|
111
|
-
end
|
111
|
+
begin
|
112
|
+
res = client.request(req)
|
113
|
+
rescue *READ_EXCEPTIONS => e
|
114
|
+
raise ReadResponseError, e.inspect
|
115
|
+
end
|
112
116
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
end
|
117
|
+
yield res
|
118
|
+
ensure
|
119
|
+
client&.finish
|
120
|
+
end
|
118
121
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
+
def execute(req, body = nil)
|
123
|
+
t do
|
124
|
+
fmt "executing HTTP request; host=%s; port=%s; path=%s, body=%s",
|
125
|
+
@host,
|
126
|
+
@port,
|
127
|
+
req.path,
|
128
|
+
body && body.bytesize
|
122
129
|
end
|
123
130
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
end
|
131
|
+
if body
|
132
|
+
body = Gzip.compress(body) if @deflate
|
133
|
+
req.body = body
|
134
|
+
end
|
129
135
|
|
130
|
-
|
131
|
-
body = Gzip.compress(body) if @deflate
|
132
|
-
req.body = body
|
133
|
-
end
|
136
|
+
http = Net::HTTP.new(@host, @port, @proxy_addr, @proxy_port, @proxy_user, @proxy_pass)
|
134
137
|
|
135
|
-
|
136
|
-
|
138
|
+
http.open_timeout = @open_timeout
|
139
|
+
http.read_timeout = @read_timeout
|
137
140
|
|
138
|
-
|
139
|
-
http.
|
141
|
+
if @ssl
|
142
|
+
http.use_ssl = true
|
140
143
|
|
141
|
-
|
142
|
-
http.use_ssl = true
|
144
|
+
http.ca_file = SSL.ca_cert_file_or_default unless SSL.ca_cert_file?
|
143
145
|
|
144
|
-
|
145
|
-
|
146
|
-
end
|
146
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
147
|
+
end
|
147
148
|
|
148
|
-
|
149
|
+
do_request(http, req) do |res|
|
150
|
+
unless res.code =~ /2\d\d/
|
151
|
+
debug "server responded with #{res.code}"
|
152
|
+
t { fmt "body=%s", res.body }
|
149
153
|
end
|
150
154
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
155
|
+
Response.new(res.code.to_i, res, res.body)
|
156
|
+
end
|
157
|
+
rescue Exception => e
|
158
|
+
error "http %s %s failed; error=%s; msg=%s", req.method, req.path, e.class, e.message
|
159
|
+
t { e.backtrace.join("\n") }
|
160
|
+
ErrorResponse.new(req, e)
|
161
|
+
end
|
156
162
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
@status = status
|
170
|
-
@headers = headers
|
171
|
-
|
172
|
-
if (headers[CONTENT_TYPE] || "").include?(APPLICATION_JSON)
|
173
|
-
begin
|
174
|
-
@body = JSON.parse(body)
|
175
|
-
rescue JSON::ParserError
|
176
|
-
@body = body # not really JSON I guess
|
177
|
-
end
|
178
|
-
else
|
179
|
-
@body = body
|
163
|
+
class Response
|
164
|
+
attr_reader :status, :headers, :body, :exception
|
165
|
+
|
166
|
+
def initialize(status, headers, body)
|
167
|
+
@status = status
|
168
|
+
@headers = headers
|
169
|
+
|
170
|
+
if (headers[CONTENT_TYPE] || "").include?(APPLICATION_JSON)
|
171
|
+
begin
|
172
|
+
@body = JSON.parse(body)
|
173
|
+
rescue JSON::ParserError
|
174
|
+
@body = body # not really JSON I guess
|
180
175
|
end
|
176
|
+
else
|
177
|
+
@body = body
|
181
178
|
end
|
179
|
+
end
|
182
180
|
|
183
|
-
|
184
|
-
|
185
|
-
|
181
|
+
def success?
|
182
|
+
status >= 200 && status < 300
|
183
|
+
end
|
186
184
|
|
187
|
-
|
188
|
-
|
189
|
-
|
185
|
+
def to_s
|
186
|
+
body.to_s
|
187
|
+
end
|
190
188
|
|
191
|
-
|
192
|
-
|
193
|
-
|
189
|
+
def get(key)
|
190
|
+
body.dig(*key.split(".")) if body.is_a?(Hash)
|
191
|
+
end
|
194
192
|
|
195
|
-
|
196
|
-
|
197
|
-
|
193
|
+
def respond_to_missing?(name, include_all = false)
|
194
|
+
super || body.respond_to?(name, include_all)
|
195
|
+
end
|
198
196
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
end
|
197
|
+
def method_missing(name, *args, &blk)
|
198
|
+
if respond_to_missing?(name)
|
199
|
+
body.send(name, *args, &blk)
|
200
|
+
else
|
201
|
+
super
|
205
202
|
end
|
206
203
|
end
|
204
|
+
end
|
207
205
|
|
208
|
-
|
206
|
+
ErrorResponse =
|
207
|
+
Struct.new(:request, :exception) do
|
209
208
|
def status
|
210
209
|
nil
|
211
210
|
end
|
@@ -14,9 +14,7 @@ module Skylight
|
|
14
14
|
# Try to avoid writing to STDOUT/STDERR twice
|
15
15
|
logger_logdev = @logger.instance_variable_get(:@logdev)
|
16
16
|
logger_out = logger_logdev.respond_to?(:dev) ? logger_logdev.dev : nil
|
17
|
-
if logger_out != $stdout && logger_out != $stderr
|
18
|
-
@logger.<<(*args)
|
19
|
-
end
|
17
|
+
@logger.<<(*args) if logger_out != $stdout && logger_out != $stderr
|
20
18
|
end
|
21
19
|
|
22
20
|
def close; end
|
@@ -85,8 +83,8 @@ module Skylight
|
|
85
83
|
|
86
84
|
alias log_trace trace
|
87
85
|
alias log_debug debug
|
88
|
-
alias log_info
|
89
|
-
alias log_warn
|
86
|
+
alias log_info info
|
87
|
+
alias log_warn warn
|
90
88
|
alias log_error error
|
91
89
|
|
92
90
|
# Alias for `Kernel#sprintf`
|
@@ -123,7 +121,7 @@ module Skylight
|
|
123
121
|
else
|
124
122
|
Kernel.warn "Invalid logger"
|
125
123
|
end
|
126
|
-
|
124
|
+
# Fallback to stderr for warn and error levels
|
127
125
|
elsif %i[warn error].include?(level)
|
128
126
|
$stderr.puts format("[SKYLIGHT] #{msg}", *args)
|
129
127
|
end
|