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/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
|