skylight 1.0.0.beta4 → 1.0.0.beta5
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 +33 -20
- data/bin/skylight +1 -1
- data/lib/skylight/api.rb +69 -29
- data/lib/skylight/cli.rb +78 -109
- data/lib/skylight/cli/doctor.rb +132 -0
- data/lib/skylight/cli/helpers.rb +32 -0
- data/lib/skylight/config.rb +131 -68
- data/lib/skylight/core.rb +3 -1
- data/lib/skylight/instrumenter.rb +5 -32
- data/lib/skylight/normalizers/action_controller/process_action.rb +12 -4
- data/lib/skylight/normalizers/active_record/sql.rb +0 -17
- data/lib/skylight/normalizers/grape/endpoint.rb +1 -1
- data/lib/skylight/probes/action_controller.rb +9 -2
- data/lib/skylight/probes/sequel.rb +8 -5
- data/lib/skylight/probes/sinatra.rb +3 -1
- data/lib/skylight/railtie.rb +2 -4
- data/lib/skylight/subscriber.rb +5 -2
- data/lib/skylight/util/logging.rb +8 -2
- data/lib/skylight/util/native_ext_fetcher.rb +4 -3
- data/lib/skylight/util/proxy.rb +12 -0
- data/lib/skylight/version.rb +1 -1
- metadata +6 -7
- data/lib/sql_lexer.rb +0 -6
- data/lib/sql_lexer/lexer.rb +0 -579
- data/lib/sql_lexer/string_scanner.rb +0 -11
- data/lib/sql_lexer/version.rb +0 -3
@@ -0,0 +1,32 @@
|
|
1
|
+
module Skylight
|
2
|
+
module CLI
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
# Duplicated below
|
8
|
+
def rails_rb
|
9
|
+
File.expand_path("config/application.rb")
|
10
|
+
end
|
11
|
+
|
12
|
+
def is_rails?
|
13
|
+
File.exist?(rails_rb)
|
14
|
+
end
|
15
|
+
|
16
|
+
def config
|
17
|
+
# Calling .load checks ENV variables
|
18
|
+
@config ||= Config.load
|
19
|
+
end
|
20
|
+
|
21
|
+
# Sets the output padding while executing a block and resets it.
|
22
|
+
#
|
23
|
+
def indent(count = 1, &block)
|
24
|
+
orig_padding = shell.padding
|
25
|
+
shell.padding += count
|
26
|
+
yield
|
27
|
+
shell.padding = orig_padding
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/skylight/config.rb
CHANGED
@@ -3,26 +3,30 @@ require 'fileutils'
|
|
3
3
|
require 'thread'
|
4
4
|
require 'openssl'
|
5
5
|
require 'erb'
|
6
|
+
require 'json'
|
6
7
|
require 'skylight/util/deploy'
|
7
8
|
require 'skylight/util/hostname'
|
8
9
|
require 'skylight/util/logging'
|
9
10
|
require 'skylight/util/platform'
|
10
11
|
require 'skylight/util/ssl'
|
12
|
+
require 'skylight/util/proxy'
|
11
13
|
|
12
14
|
module Skylight
|
13
15
|
class Config
|
16
|
+
include Util::Logging
|
17
|
+
|
14
18
|
# @api private
|
15
19
|
MUTEX = Mutex.new
|
16
20
|
|
17
21
|
# Map environment variable keys with Skylight configuration keys
|
18
22
|
ENV_TO_KEY = {
|
19
23
|
# == Authentication ==
|
20
|
-
'AUTHENTICATION' => :
|
24
|
+
'AUTHENTICATION' => :authentication,
|
21
25
|
|
22
26
|
# == App settings ==
|
23
|
-
'ROOT' => :
|
24
|
-
'HOSTNAME' => :
|
25
|
-
'SESSION_TOKEN' => :
|
27
|
+
'ROOT' => :root,
|
28
|
+
'HOSTNAME' => :hostname,
|
29
|
+
'SESSION_TOKEN' => :session_token,
|
26
30
|
|
27
31
|
# == Deploy settings ==
|
28
32
|
'DEPLOY_ID' => :'deploy.id',
|
@@ -30,29 +34,30 @@ module Skylight
|
|
30
34
|
'DEPLOY_DESCRIPTION' => :'deploy.description',
|
31
35
|
|
32
36
|
# == Logging ==
|
33
|
-
'LOG_FILE' => :
|
34
|
-
'LOG_LEVEL' => :
|
35
|
-
'ALERT_LOG_FILE' => :
|
36
|
-
'LOG_SQL_PARSE_ERRORS' => :
|
37
|
+
'LOG_FILE' => :log_file,
|
38
|
+
'LOG_LEVEL' => :log_level,
|
39
|
+
'ALERT_LOG_FILE' => :alert_log_file,
|
40
|
+
'LOG_SQL_PARSE_ERRORS' => :log_sql_parse_errors,
|
37
41
|
|
38
42
|
# == Proxy ==
|
39
|
-
'PROXY_URL' => :
|
43
|
+
'PROXY_URL' => :proxy_url,
|
40
44
|
|
41
45
|
# == Instrumenter ==
|
42
|
-
"IGNORED_ENDPOINT" => :
|
43
|
-
"IGNORED_ENDPOINTS" => :
|
44
|
-
"
|
45
|
-
"SEPARATE_FORMATS" => :'separate_formats',
|
46
|
+
"IGNORED_ENDPOINT" => :ignored_endpoint,
|
47
|
+
"IGNORED_ENDPOINTS" => :ignored_endpoints,
|
48
|
+
"ENABLE_SEGMENTS" => :enable_segments,
|
46
49
|
|
47
50
|
# == Skylight Remote ==
|
48
|
-
"AUTH_URL" => :
|
49
|
-
"
|
50
|
-
"
|
51
|
-
"
|
52
|
-
"
|
53
|
-
"
|
54
|
-
"
|
55
|
-
"
|
51
|
+
"AUTH_URL" => :auth_url,
|
52
|
+
"APP_CREATE_URL" => :app_create_url,
|
53
|
+
"VALIDATION_URL" => :validation_url,
|
54
|
+
"AUTH_HTTP_DEFLATE" => :auth_http_deflate,
|
55
|
+
"AUTH_HTTP_CONNECT_TIMEOUT" => :auth_http_connect_timeout,
|
56
|
+
"AUTH_HTTP_READ_TIMEOUT" => :auth_http_read_timeout,
|
57
|
+
"REPORT_URL" => :report_url,
|
58
|
+
"REPORT_HTTP_DEFLATE" => :report_http_deflate,
|
59
|
+
"REPORT_HTTP_CONNECT_TIMEOUT" => :report_http_connect_timeout,
|
60
|
+
"REPORT_HTTP_READ_TIMEOUT" => :report_http_read_timeout,
|
56
61
|
|
57
62
|
# == Native agent settings ==
|
58
63
|
#
|
@@ -89,15 +94,16 @@ module Skylight
|
|
89
94
|
|
90
95
|
# Default values for Skylight configuration keys
|
91
96
|
DEFAULTS = {
|
92
|
-
:
|
93
|
-
:
|
94
|
-
:'
|
95
|
-
:'
|
96
|
-
:
|
97
|
-
:
|
98
|
-
:'
|
99
|
-
:
|
100
|
-
:
|
97
|
+
:auth_url => 'https://auth.skylight.io/agent',
|
98
|
+
:app_create_url => 'https://www.skylight.io/apps',
|
99
|
+
:validation_url => 'https://auth.skylight.io/agent/config',
|
100
|
+
:'daemon.lazy_start' => true,
|
101
|
+
:log_file => '-'.freeze,
|
102
|
+
:log_level => 'INFO'.freeze,
|
103
|
+
:alert_log_file => '-'.freeze,
|
104
|
+
:log_sql_parse_errors => false,
|
105
|
+
:enable_segments => false,
|
106
|
+
:hostname => Util::Hostname.default_hostname,
|
101
107
|
:'heroku.dyno_info_path' => '/etc/heroku/dyno'
|
102
108
|
}
|
103
109
|
|
@@ -116,25 +122,30 @@ module Skylight
|
|
116
122
|
DEFAULTS.freeze
|
117
123
|
|
118
124
|
REQUIRED = {
|
119
|
-
:
|
120
|
-
:
|
121
|
-
:
|
125
|
+
authentication: "authentication token",
|
126
|
+
hostname: "server hostname",
|
127
|
+
auth_url: "authentication url",
|
128
|
+
validation_url: "config validation url" }
|
129
|
+
|
130
|
+
SERVER_VALIDATE = [
|
131
|
+
:enable_segments
|
132
|
+
]
|
122
133
|
|
123
134
|
NATIVE_ENV = [
|
124
|
-
:
|
125
|
-
:
|
126
|
-
:
|
127
|
-
:
|
128
|
-
:
|
129
|
-
:
|
130
|
-
:
|
131
|
-
:
|
132
|
-
:
|
133
|
-
:
|
134
|
-
:
|
135
|
-
:
|
136
|
-
:
|
137
|
-
:
|
135
|
+
:version,
|
136
|
+
:root,
|
137
|
+
:hostname,
|
138
|
+
:deploy_id,
|
139
|
+
:session_token,
|
140
|
+
:proxy_url,
|
141
|
+
:auth_url,
|
142
|
+
:auth_http_deflate,
|
143
|
+
:auth_http_connect_timeout,
|
144
|
+
:auth_http_read_timeout,
|
145
|
+
:report_url,
|
146
|
+
:report_http_deflate,
|
147
|
+
:report_http_connect_timeout,
|
148
|
+
:report_http_read_timeout,
|
138
149
|
:'daemon.lazy_start',
|
139
150
|
:'daemon.exec_path',
|
140
151
|
:'daemon.lib_path',
|
@@ -245,7 +256,10 @@ module Skylight
|
|
245
256
|
|
246
257
|
return ret unless env
|
247
258
|
|
248
|
-
|
259
|
+
# Only set if it exists, we don't want to set to a nil value
|
260
|
+
if proxy_url = Util::Proxy.detect_url(env)
|
261
|
+
ret[:proxy_url] = proxy_url
|
262
|
+
end
|
249
263
|
|
250
264
|
env.each do |k, val|
|
251
265
|
# Support deprecated SK_ key prefix
|
@@ -267,28 +281,19 @@ module Skylight
|
|
267
281
|
ret
|
268
282
|
end
|
269
283
|
|
270
|
-
def
|
271
|
-
|
272
|
-
u = "http://#{u}" unless u =~ %r[://]
|
273
|
-
u
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
# @api private
|
278
|
-
def skip_validation?
|
279
|
-
!!get(:skip_validation)
|
284
|
+
def api
|
285
|
+
@api ||= Api.new(self)
|
280
286
|
end
|
281
287
|
|
282
288
|
# @api private
|
283
289
|
def validate!
|
284
|
-
return true if skip_validation?
|
285
|
-
|
286
290
|
REQUIRED.each do |k, v|
|
287
291
|
unless get(k)
|
288
292
|
raise ConfigError, "#{v} required"
|
289
293
|
end
|
290
294
|
end
|
291
295
|
|
296
|
+
# TODO: Move this out of the validate! method: https://github.com/tildeio/direwolf-agent/issues/273
|
292
297
|
# FIXME: Why not set the sockdir_path and pidfile_path explicitly?
|
293
298
|
# That way we don't have to keep this in sync with the Rust repo.
|
294
299
|
sockdir_path = self[:'daemon.sockdir_path'] || File.expand_path('.')
|
@@ -299,6 +304,50 @@ module Skylight
|
|
299
304
|
true
|
300
305
|
end
|
301
306
|
|
307
|
+
def validate_with_server
|
308
|
+
res = api.validate_config
|
309
|
+
|
310
|
+
unless res.token_valid?
|
311
|
+
warn("Invalid authentication token")
|
312
|
+
return false
|
313
|
+
end
|
314
|
+
|
315
|
+
if res.is_error_response?
|
316
|
+
warn("Unable to reach server for config validation")
|
317
|
+
end
|
318
|
+
|
319
|
+
unless res.config_valid?
|
320
|
+
warn("Invalid configuration") unless res.is_error_response?
|
321
|
+
if errors = res.validation_errors
|
322
|
+
errors.each do |k,v|
|
323
|
+
warn(" #{k} #{v}")
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
corrected_config = res.corrected_config
|
328
|
+
unless corrected_config
|
329
|
+
# Use defaults if no corrected config is available. This will happen if the request failed.
|
330
|
+
corrected_config = Hash[SERVER_VALIDATE.map{|k| [k, DEFAULTS[k]] }]
|
331
|
+
end
|
332
|
+
|
333
|
+
config_to_update = corrected_config.select{|k,v| get(k) != v }
|
334
|
+
unless config_to_update.empty?
|
335
|
+
info("Updating config values:")
|
336
|
+
config_to_update.each do |k,v|
|
337
|
+
info(" setting #{k} to #{v}")
|
338
|
+
|
339
|
+
# This is a weird way to handle priorities
|
340
|
+
# See https://github.com/tildeio/direwolf-agent/issues/275
|
341
|
+
k = "#{environment}.#{k}" if environment
|
342
|
+
|
343
|
+
set(k, v)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
return true
|
349
|
+
end
|
350
|
+
|
302
351
|
def check_permissions(pidfile, sockdir_path)
|
303
352
|
pidfile_root = File.dirname(pidfile)
|
304
353
|
|
@@ -401,13 +450,23 @@ module Skylight
|
|
401
450
|
end
|
402
451
|
end
|
403
452
|
|
453
|
+
def to_json
|
454
|
+
JSON.generate(
|
455
|
+
config: {
|
456
|
+
priority: @priority,
|
457
|
+
values: @values
|
458
|
+
}
|
459
|
+
)
|
460
|
+
end
|
461
|
+
|
404
462
|
def to_native_env
|
405
463
|
ret = []
|
406
464
|
|
407
465
|
ret << "SKYLIGHT_AUTHENTICATION" << authentication_with_deploy
|
408
466
|
|
409
467
|
NATIVE_ENV.each do |key|
|
410
|
-
|
468
|
+
value = send_or_get(key)
|
469
|
+
unless value.nil?
|
411
470
|
env_key = ENV_TO_KEY.key(key) || key.upcase
|
412
471
|
ret << "SKYLIGHT_#{env_key}" << cast_for_env(value)
|
413
472
|
end
|
@@ -454,7 +513,7 @@ authentication: #{self[:authentication]}
|
|
454
513
|
def ignored_endpoints
|
455
514
|
@ignored_endpoints ||=
|
456
515
|
begin
|
457
|
-
ignored_endpoints = get(:
|
516
|
+
ignored_endpoints = get(:ignored_endpoints)
|
458
517
|
|
459
518
|
# If, for some odd reason you have a comma in your endpoint name, use the
|
460
519
|
# YML config instead.
|
@@ -462,7 +521,7 @@ authentication: #{self[:authentication]}
|
|
462
521
|
ignored_endpoints = ignored_endpoints.split(/\s*,\s*/)
|
463
522
|
end
|
464
523
|
|
465
|
-
val = Array(get(:
|
524
|
+
val = Array(get(:ignored_endpoint))
|
466
525
|
val.concat(Array(ignored_endpoints))
|
467
526
|
val
|
468
527
|
end
|
@@ -501,7 +560,7 @@ authentication: #{self[:authentication]}
|
|
501
560
|
begin
|
502
561
|
MUTEX.synchronize do
|
503
562
|
unless l = @alert_logger
|
504
|
-
out = get(:
|
563
|
+
out = get(:alert_log_file)
|
505
564
|
|
506
565
|
if out == '-'
|
507
566
|
out = Util::AlertLogger.new(load_logger)
|
@@ -523,12 +582,16 @@ authentication: #{self[:authentication]}
|
|
523
582
|
@alert_logger = logger
|
524
583
|
end
|
525
584
|
|
585
|
+
def on_heroku?
|
586
|
+
File.exist?(get(:'heroku.dyno_info_path'))
|
587
|
+
end
|
588
|
+
|
526
589
|
def deploy
|
527
590
|
@deploy ||= Util::Deploy.build(self)
|
528
591
|
end
|
529
592
|
|
530
|
-
def
|
531
|
-
!!get(:
|
593
|
+
def enable_segments?
|
594
|
+
!!get(:enable_segments)
|
532
595
|
end
|
533
596
|
|
534
597
|
private
|
@@ -540,7 +603,7 @@ authentication: #{self[:authentication]}
|
|
540
603
|
|
541
604
|
def load_logger
|
542
605
|
unless l = @logger
|
543
|
-
out = get(:
|
606
|
+
out = get(:log_file)
|
544
607
|
out = STDOUT if out == '-'
|
545
608
|
|
546
609
|
unless IO === out
|
@@ -550,7 +613,7 @@ authentication: #{self[:authentication]}
|
|
550
613
|
|
551
614
|
l = Logger.new(out)
|
552
615
|
l.level =
|
553
|
-
case get(:
|
616
|
+
case get(:log_level)
|
554
617
|
when /^debug$/i then Logger::DEBUG
|
555
618
|
when /^info$/i then Logger::INFO
|
556
619
|
when /^warn$/i then Logger::WARN
|
data/lib/skylight/core.rb
CHANGED
@@ -7,7 +7,9 @@ module Skylight
|
|
7
7
|
# Load the native agent
|
8
8
|
require 'skylight/native'
|
9
9
|
|
10
|
-
|
10
|
+
# Specifically check for Railtie since we've had at least one case of a
|
11
|
+
# customer having Rails defined without having all of Rails loaded.
|
12
|
+
if defined?(Rails::Railtie)
|
11
13
|
require 'skylight/railtie'
|
12
14
|
end
|
13
15
|
|
@@ -107,10 +107,9 @@ module Skylight
|
|
107
107
|
end
|
108
108
|
|
109
109
|
t { "starting instrumenter" }
|
110
|
-
@config.validate!
|
111
110
|
|
112
|
-
unless
|
113
|
-
|
111
|
+
unless config.validate_with_server
|
112
|
+
log_error "invalid config"
|
114
113
|
return
|
115
114
|
end
|
116
115
|
|
@@ -120,13 +119,13 @@ module Skylight
|
|
120
119
|
return
|
121
120
|
end
|
122
121
|
|
123
|
-
|
122
|
+
config.gc.enable
|
124
123
|
@subscriber.register!
|
125
124
|
|
126
125
|
self
|
127
126
|
|
128
127
|
rescue Exception => e
|
129
|
-
log_error "failed to start instrumenter; msg=%s; config=%s", e.message,
|
128
|
+
log_error "failed to start instrumenter; msg=%s; config=%s", e.message, config.inspect
|
130
129
|
t { e.backtrace.join("\n") }
|
131
130
|
nil
|
132
131
|
end
|
@@ -252,33 +251,7 @@ module Skylight
|
|
252
251
|
end
|
253
252
|
|
254
253
|
def ignore?(trace)
|
255
|
-
|
256
|
-
end
|
257
|
-
|
258
|
-
# Validates that the provided authentication token is valid. This is done
|
259
|
-
# by issuing a request for a session token and checking the response
|
260
|
-
def validate_authentication
|
261
|
-
# If a session token is specified, don't bother attempting to validate
|
262
|
-
if config[:session_token]
|
263
|
-
debug "using pre-generated session token"
|
264
|
-
true
|
265
|
-
else
|
266
|
-
api = Api.new(config)
|
267
|
-
api.authentication = config[:authentication]
|
268
|
-
|
269
|
-
case res = api.validate_authentication
|
270
|
-
when :ok
|
271
|
-
true
|
272
|
-
when :invalid
|
273
|
-
false
|
274
|
-
when :unknown
|
275
|
-
warn "unable to validate authentication token"
|
276
|
-
true
|
277
|
-
else
|
278
|
-
error "[BUG] unexpected validate_token result; res=%s", res
|
279
|
-
true
|
280
|
-
end
|
281
|
-
end
|
254
|
+
config.ignored_endpoints.include?(trace.endpoint)
|
282
255
|
end
|
283
256
|
|
284
257
|
end
|
@@ -16,11 +16,19 @@ module Skylight
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def normalize_after(trace, span, name, payload)
|
19
|
-
return unless config.
|
19
|
+
return unless config.enable_segments?
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
# Show 'error' if there's an unhandled exception or if the status is 4xx or 5xx
|
22
|
+
if payload[:exception] || payload[:status].to_s =~ /^[45]/
|
23
|
+
segment = "error"
|
24
|
+
# We won't have a rendered_format if it's a `head` outside of a `respond_to` block.
|
25
|
+
elsif payload[:rendered_format]
|
26
|
+
# We only show the variant if we actually have a format
|
27
|
+
segment = [payload[:rendered_format], payload[:variant]].compact.flatten.join('+')
|
28
|
+
end
|
29
|
+
|
30
|
+
if segment
|
31
|
+
trace.endpoint += "<sk-segment>#{segment}</sk-segment>"
|
24
32
|
end
|
25
33
|
end
|
26
34
|
|