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.
- 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/config.rb
CHANGED
@@ -1,36 +1,35 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
1
|
+
require "openssl"
|
2
|
+
require "skylight/util/component"
|
3
|
+
require "skylight/util/deploy"
|
4
|
+
require "skylight/core/util/platform"
|
5
|
+
require "skylight/util/hostname"
|
6
|
+
require "skylight/util/ssl"
|
7
7
|
|
8
8
|
module Skylight
|
9
9
|
class Config < Core::Config
|
10
|
-
|
11
10
|
def self.env_to_key
|
12
11
|
@env_to_key ||= super.merge(
|
13
12
|
# == Authentication ==
|
14
|
-
|
13
|
+
"AUTHENTICATION" => :authentication,
|
15
14
|
|
16
15
|
# == App settings ==
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
"ROOT" => :root,
|
17
|
+
"HOSTNAME" => :hostname,
|
18
|
+
"SESSION_TOKEN" => :session_token,
|
20
19
|
|
21
20
|
# == Component settings ==
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
"ENV" => :env,
|
22
|
+
"COMPONENT" => :component,
|
23
|
+
"REPORT_RAILS_ENV" => :report_rails_env,
|
25
24
|
|
26
25
|
# == Deploy settings ==
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
"DEPLOY_ID" => :'deploy.id',
|
27
|
+
"DEPLOY_GIT_SHA" => :'deploy.git_sha',
|
28
|
+
"DEPLOY_DESCRIPTION" => :'deploy.description',
|
30
29
|
|
31
30
|
# == Max Span Handling ==
|
32
|
-
|
33
|
-
|
31
|
+
"REPORT_MAX_SPANS_EXCEEDED" => :report_max_spans_exceeded,
|
32
|
+
"PRUNE_LARGE_TRACES" => :prune_large_traces,
|
34
33
|
|
35
34
|
# == Instrumenter ==
|
36
35
|
"IGNORED_ENDPOINT" => :ignored_endpoint,
|
@@ -75,8 +74,8 @@ module Skylight
|
|
75
74
|
|
76
75
|
# == Legacy env vars ==
|
77
76
|
#
|
78
|
-
|
79
|
-
|
77
|
+
"AGENT_LOCKFILE" => :'agent.lockfile',
|
78
|
+
"AGENT_SOCKFILE_PATH" => :'agent.sockfile_path'
|
80
79
|
)
|
81
80
|
end
|
82
81
|
|
@@ -84,18 +83,18 @@ module Skylight
|
|
84
83
|
def self.default_values
|
85
84
|
@default_values ||= begin
|
86
85
|
ret = super.merge(
|
87
|
-
:
|
88
|
-
:
|
89
|
-
:
|
90
|
-
:
|
91
|
-
|
92
|
-
:
|
93
|
-
:
|
94
|
-
:
|
95
|
-
:
|
86
|
+
auth_url: "https://auth.skylight.io/agent",
|
87
|
+
app_create_url: "https://www.skylight.io/apps",
|
88
|
+
merges_url: "https://www.skylight.io/merges",
|
89
|
+
validation_url: "https://auth.skylight.io/agent/config",
|
90
|
+
'daemon.lazy_start': true,
|
91
|
+
hostname: Util::Hostname.default_hostname,
|
92
|
+
report_max_spans_exceeded: false,
|
93
|
+
prune_large_traces: true,
|
94
|
+
report_rails_env: true
|
96
95
|
)
|
97
96
|
|
98
|
-
if Core::Util::Platform::OS !=
|
97
|
+
if Core::Util::Platform::OS != "darwin"
|
99
98
|
ret[:'daemon.ssl_cert_path'] = Util::SSL.ca_cert_file_or_default
|
100
99
|
ret[:'daemon.ssl_cert_dir'] = Util::SSL.ca_cert_dir
|
101
100
|
end
|
@@ -104,7 +103,7 @@ module Skylight
|
|
104
103
|
native_path = Skylight.libskylight_path
|
105
104
|
|
106
105
|
ret[:'daemon.lib_path'] = native_path
|
107
|
-
ret[:'daemon.exec_path'] = File.join(native_path,
|
106
|
+
ret[:'daemon.exec_path'] = File.join(native_path, "skylightd")
|
108
107
|
end
|
109
108
|
|
110
109
|
ret
|
@@ -121,53 +120,53 @@ module Skylight
|
|
121
120
|
end
|
122
121
|
|
123
122
|
def self.native_env_keys
|
124
|
-
@native_env_keys ||= super + [
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
123
|
+
@native_env_keys ||= super + %i[
|
124
|
+
version
|
125
|
+
root
|
126
|
+
hostname
|
127
|
+
session_token
|
128
|
+
auth_url
|
129
|
+
auth_http_deflate
|
130
|
+
auth_http_connect_timeout
|
131
|
+
auth_http_read_timeout
|
132
|
+
report_url
|
133
|
+
report_http_deflate
|
134
|
+
report_http_connect_timeout
|
135
|
+
report_http_read_timeout
|
136
|
+
report_http_disabled
|
137
|
+
daemon.lazy_start
|
138
|
+
daemon.exec_path
|
139
|
+
daemon.lib_path
|
140
|
+
daemon.pidfile_path
|
141
|
+
daemon.sockdir_path
|
142
|
+
daemon.batch_queue_depth
|
143
|
+
daemon.batch_sample_size
|
144
|
+
daemon.batch_flush_interval
|
145
|
+
daemon.tick_interval
|
146
|
+
daemon.sanity_check_interval
|
147
|
+
daemon.inactivity_timeout
|
148
|
+
daemon.max_connect_tries
|
149
|
+
daemon.connect_try_window
|
150
|
+
daemon.max_prespawn_jitter
|
151
|
+
daemon.wait_timeout
|
152
|
+
daemon.client_check_interval
|
153
|
+
daemon.client_queue_depth
|
154
|
+
daemon.client_write_timeout
|
155
|
+
daemon.ssl_cert_path
|
156
|
+
daemon.ssl_cert_dir
|
158
157
|
]
|
159
158
|
end
|
160
159
|
|
161
160
|
def self.legacy_keys
|
162
161
|
@legacy_keys ||= super.merge(
|
163
|
-
|
164
|
-
|
162
|
+
'agent.sockfile_path': :'daemon.sockdir_path',
|
163
|
+
'agent.lockfile': :'daemon.pidfile_path'
|
165
164
|
)
|
166
165
|
end
|
167
166
|
|
168
167
|
def self.validators
|
169
168
|
@validators ||= super.merge(
|
170
|
-
|
169
|
+
'agent.interval': [->(v, _c) { v.is_a?(Integer) && v > 0 }, "must be an integer greater than 0"]
|
171
170
|
)
|
172
171
|
end
|
173
172
|
|
@@ -183,8 +182,8 @@ module Skylight
|
|
183
182
|
# TODO: Move this out of the validate! method: https://github.com/tildeio/direwolf-agent/issues/273
|
184
183
|
# FIXME: Why not set the sockdir_path and pidfile_path explicitly?
|
185
184
|
# That way we don't have to keep this in sync with the Rust repo.
|
186
|
-
sockdir_path = File.expand_path(self[:'daemon.sockdir_path'] ||
|
187
|
-
pidfile_path = File.expand_path(self[:'daemon.pidfile_path'] ||
|
185
|
+
sockdir_path = File.expand_path(self[:'daemon.sockdir_path'] || ".", root)
|
186
|
+
pidfile_path = File.expand_path(self[:'daemon.pidfile_path'] || "skylight.pid", sockdir_path)
|
188
187
|
|
189
188
|
check_file_permissions(pidfile_path, "daemon.pidfile_path or daemon.sockdir_path")
|
190
189
|
check_sockdir_permissions(sockdir_path)
|
@@ -200,28 +199,23 @@ module Skylight
|
|
200
199
|
return false
|
201
200
|
end
|
202
201
|
|
203
|
-
if res.
|
202
|
+
if res.error_response?
|
204
203
|
warn("Unable to reach server for config validation")
|
205
204
|
end
|
206
205
|
|
207
206
|
unless res.config_valid?
|
208
|
-
warn("Invalid configuration") unless res.
|
209
|
-
|
210
|
-
|
211
|
-
warn(" #{k} #{v}")
|
212
|
-
end
|
207
|
+
warn("Invalid configuration") unless res.error_response?
|
208
|
+
res.validation_errors.each do |k, v|
|
209
|
+
warn(" #{k}: #{v}")
|
213
210
|
end
|
214
211
|
|
215
|
-
|
216
|
-
unless corrected_config
|
217
|
-
# Use defaults if no corrected config is available. This will happen if the request failed.
|
218
|
-
corrected_config = Hash[self.class.server_validated_keys.map{|k| [k, [k]] }]
|
219
|
-
end
|
212
|
+
return false if res.forbidden?
|
220
213
|
|
221
|
-
|
214
|
+
corrected_config = res.corrected_config
|
215
|
+
config_to_update = corrected_config.reject { |k, v| get(k) == v }
|
222
216
|
unless config_to_update.empty?
|
223
217
|
info("Updating config values:")
|
224
|
-
config_to_update.each do |k,v|
|
218
|
+
config_to_update.each do |k, v|
|
225
219
|
info(" setting #{k} to #{v}")
|
226
220
|
|
227
221
|
# This is a weird way to handle priorities
|
@@ -233,7 +227,7 @@ module Skylight
|
|
233
227
|
end
|
234
228
|
end
|
235
229
|
|
236
|
-
|
230
|
+
true
|
237
231
|
end
|
238
232
|
|
239
233
|
def check_sockdir_permissions(sockdir_path)
|
@@ -261,7 +255,7 @@ module Skylight
|
|
261
255
|
def write(path)
|
262
256
|
FileUtils.mkdir_p(File.dirname(path))
|
263
257
|
|
264
|
-
File.open(path,
|
258
|
+
File.open(path, "w") do |f|
|
265
259
|
f.puts <<-YAML
|
266
260
|
---
|
267
261
|
# The authentication token for the application.
|
@@ -280,7 +274,7 @@ authentication: #{self[:authentication]}
|
|
280
274
|
token = get(:authentication)
|
281
275
|
|
282
276
|
if token
|
283
|
-
meta = {
|
277
|
+
meta = {}
|
284
278
|
meta.merge!(deploy.to_query_hash) if deploy
|
285
279
|
meta[:component] = component.to_s if component
|
286
280
|
meta[:reporting_env] = true if reporting_env?
|
@@ -298,22 +292,42 @@ authentication: #{self[:authentication]}
|
|
298
292
|
end
|
299
293
|
|
300
294
|
def component
|
301
|
-
@component ||= Util::Component.new(
|
295
|
+
@component ||= Util::Component.new(
|
296
|
+
get(:env),
|
297
|
+
get(:component) || get(:worker_component)
|
298
|
+
)
|
302
299
|
rescue ArgumentError => e
|
303
300
|
raise Core::ConfigError, e.message
|
304
301
|
end
|
305
302
|
|
306
|
-
|
303
|
+
def worker_context?
|
304
|
+
component.worker?
|
305
|
+
end
|
307
306
|
|
308
|
-
def
|
309
|
-
|
310
|
-
`stat -f -L -c %T #{path} 2>&1`.strip == 'nfs'
|
307
|
+
def web_context?
|
308
|
+
component.web?
|
311
309
|
end
|
312
310
|
|
313
|
-
def
|
314
|
-
|
315
|
-
|
316
|
-
|
311
|
+
def as_json(*)
|
312
|
+
{
|
313
|
+
config: {
|
314
|
+
priority: @priority.merge(component.as_json),
|
315
|
+
values: @values
|
316
|
+
}
|
317
|
+
}
|
317
318
|
end
|
319
|
+
|
320
|
+
private
|
321
|
+
|
322
|
+
def check_nfs(path)
|
323
|
+
# Should work on most *nix, though not on OS X
|
324
|
+
`stat -f -L -c %T #{path} 2>&1`.strip == "nfs"
|
325
|
+
end
|
326
|
+
|
327
|
+
def reporting_env?
|
328
|
+
# true if env was explicitly set,
|
329
|
+
# or if we are auto-detecting via the opt-in SKYLIGHT_REPORT_RAILS_ENV=true
|
330
|
+
!!(get(:report_rails_env) || get(:env))
|
331
|
+
end
|
318
332
|
end
|
319
333
|
end
|
data/lib/skylight/errors.rb
CHANGED
@@ -1,27 +1,26 @@
|
|
1
1
|
module Skylight
|
2
2
|
class NativeError < StandardError
|
3
|
-
|
4
|
-
@@classes = { }
|
3
|
+
@classes = {}
|
5
4
|
|
6
5
|
def self.register(code, name, message)
|
7
|
-
if
|
6
|
+
if @classes.key?(code)
|
8
7
|
raise "Duplicate error class code: #{code}; name=#{name}"
|
9
8
|
end
|
10
9
|
|
11
|
-
Skylight.module_eval <<-
|
10
|
+
Skylight.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
12
11
|
class #{name}Error < NativeError
|
13
12
|
def self.code; #{code}; end
|
14
13
|
def self.message; #{message.to_json}; end
|
15
14
|
end
|
16
|
-
|
15
|
+
RUBY
|
17
16
|
|
18
17
|
klass = Skylight.const_get("#{name}Error")
|
19
18
|
|
20
|
-
|
19
|
+
@classes[code] = klass
|
21
20
|
end
|
22
21
|
|
23
22
|
def self.for_code(code)
|
24
|
-
|
23
|
+
@classes[code] || self
|
25
24
|
end
|
26
25
|
|
27
26
|
attr_reader :method_name
|
@@ -36,7 +35,7 @@ module Skylight
|
|
36
35
|
|
37
36
|
def initialize(method_name)
|
38
37
|
@method_name = method_name
|
39
|
-
super(
|
38
|
+
super(format("[E%<code>04d] %<message>s [%<meth>s]", code: code, message: message, meth: method_name))
|
40
39
|
end
|
41
40
|
|
42
41
|
def code
|
@@ -44,7 +43,7 @@ module Skylight
|
|
44
43
|
end
|
45
44
|
|
46
45
|
def formatted_code
|
47
|
-
"%04d"
|
46
|
+
format("%04d", code)
|
48
47
|
end
|
49
48
|
|
50
49
|
# E0003
|
@@ -53,5 +52,4 @@ module Skylight
|
|
53
52
|
# E0004
|
54
53
|
register(4, "SqlLex", "Failed to lex SQL query.")
|
55
54
|
end
|
56
|
-
|
57
55
|
end
|
data/lib/skylight/helpers.rb
CHANGED
@@ -6,14 +6,13 @@ module Skylight
|
|
6
6
|
# into the class that you will be instrumenting. Then, annotate each method that
|
7
7
|
# you wish to instrument with {Skylight::Helpers::ClassMethods#instrument_method instrument_method}.
|
8
8
|
module Helpers
|
9
|
-
|
10
9
|
# @see Skylight::Helpers
|
11
10
|
module ClassMethods
|
12
11
|
# @api private
|
13
12
|
def method_added(name)
|
14
13
|
super
|
15
14
|
|
16
|
-
if opts = @__sk_instrument_next_method
|
15
|
+
if (opts = @__sk_instrument_next_method)
|
17
16
|
@__sk_instrument_next_method = nil
|
18
17
|
instrument_method(name, opts)
|
19
18
|
end
|
@@ -23,7 +22,7 @@ module Skylight
|
|
23
22
|
def singleton_method_added(name)
|
24
23
|
super
|
25
24
|
|
26
|
-
if opts = @__sk_instrument_next_method
|
25
|
+
if (opts = @__sk_instrument_next_method)
|
27
26
|
@__sk_instrument_next_method = nil
|
28
27
|
instrument_class_method(name, opts)
|
29
28
|
end
|
@@ -79,10 +78,10 @@ module Skylight
|
|
79
78
|
# end
|
80
79
|
# end
|
81
80
|
def instrument_method(*args)
|
82
|
-
opts = args.pop if
|
81
|
+
opts = args.pop if args.last.is_a?(Hash)
|
83
82
|
|
84
|
-
if name = args.pop
|
85
|
-
title = "#{
|
83
|
+
if (name = args.pop)
|
84
|
+
title = "#{self}##{name}"
|
86
85
|
__sk_instrument_method_on(self, name, title, opts || {})
|
87
86
|
else
|
88
87
|
@__sk_instrument_next_method = opts || {}
|
@@ -125,46 +124,46 @@ module Skylight
|
|
125
124
|
# instrument_class_method :my_method, title: 'Expensive work'
|
126
125
|
# end
|
127
126
|
def instrument_class_method(name, opts = {})
|
128
|
-
title = "#{
|
127
|
+
title = "#{self}.#{name}"
|
129
128
|
__sk_instrument_method_on(__sk_singleton_class, name, title, opts || {})
|
130
129
|
end
|
131
130
|
|
132
|
-
|
131
|
+
private
|
133
132
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
133
|
+
def __sk_instrument_method_on(klass, name, title, opts)
|
134
|
+
category = (opts[:category] || "app.method").to_s
|
135
|
+
title = (opts[:title] || title).to_s
|
136
|
+
desc = opts[:description].to_s if opts[:description]
|
138
137
|
|
139
|
-
|
140
|
-
|
138
|
+
klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
139
|
+
alias_method :"before_instrument_#{name}", :"#{name}"
|
141
140
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
141
|
+
def #{name}(*args, &blk)
|
142
|
+
span = Skylight.instrument(
|
143
|
+
category: :"#{category}",
|
144
|
+
title: #{title.inspect},
|
145
|
+
description: #{desc.inspect})
|
147
146
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
147
|
+
meta = {}
|
148
|
+
begin
|
149
|
+
send(:before_instrument_#{name}, *args, &blk)
|
150
|
+
rescue Exception => e
|
151
|
+
meta[:exception_object] = e
|
152
|
+
raise e
|
153
|
+
ensure
|
154
|
+
Skylight.done(span, meta) if span
|
155
|
+
end
|
156
156
|
end
|
157
|
-
|
158
|
-
|
159
|
-
end
|
157
|
+
RUBY
|
158
|
+
end
|
160
159
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
160
|
+
if respond_to?(:singleton_class)
|
161
|
+
alias __sk_singleton_class singleton_class
|
162
|
+
else
|
163
|
+
def __sk_singleton_class
|
164
|
+
class << self; self; end
|
165
|
+
end
|
166
166
|
end
|
167
|
-
end
|
168
167
|
end
|
169
168
|
|
170
169
|
# @api private
|
@@ -174,6 +173,5 @@ module Skylight
|
|
174
173
|
extend ClassMethods
|
175
174
|
end
|
176
175
|
end
|
177
|
-
|
178
176
|
end
|
179
177
|
end
|