truex-skylight 0.6.0
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 +7 -0
- data/CHANGELOG.md +277 -0
- data/CLA.md +9 -0
- data/CONTRIBUTING.md +1 -0
- data/LICENSE.md +79 -0
- data/README.md +4 -0
- data/bin/skylight +3 -0
- data/ext/extconf.rb +186 -0
- data/ext/libskylight.yml +6 -0
- data/ext/skylight_memprof.c +115 -0
- data/ext/skylight_native.c +416 -0
- data/ext/skylight_native.h +20 -0
- data/lib/skylight.rb +2 -0
- data/lib/skylight/api.rb +79 -0
- data/lib/skylight/cli.rb +146 -0
- data/lib/skylight/compat.rb +47 -0
- data/lib/skylight/config.rb +498 -0
- data/lib/skylight/core.rb +122 -0
- data/lib/skylight/data/cacert.pem +3894 -0
- data/lib/skylight/formatters/http.rb +17 -0
- data/lib/skylight/gc.rb +107 -0
- data/lib/skylight/helpers.rb +137 -0
- data/lib/skylight/instrumenter.rb +290 -0
- data/lib/skylight/middleware.rb +75 -0
- data/lib/skylight/native.rb +69 -0
- data/lib/skylight/normalizers.rb +133 -0
- data/lib/skylight/normalizers/action_controller/process_action.rb +35 -0
- data/lib/skylight/normalizers/action_controller/send_file.rb +76 -0
- data/lib/skylight/normalizers/action_view/render_collection.rb +18 -0
- data/lib/skylight/normalizers/action_view/render_partial.rb +18 -0
- data/lib/skylight/normalizers/action_view/render_template.rb +18 -0
- data/lib/skylight/normalizers/active_record/sql.rb +79 -0
- data/lib/skylight/normalizers/active_support/cache.rb +50 -0
- data/lib/skylight/normalizers/active_support/cache_clear.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_decrement.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_delete.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_exist.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_fetch_hit.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_generate.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_increment.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_read.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_read_multi.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_write.rb +16 -0
- data/lib/skylight/normalizers/default.rb +21 -0
- data/lib/skylight/normalizers/moped/query.rb +141 -0
- data/lib/skylight/probes.rb +91 -0
- data/lib/skylight/probes/excon.rb +25 -0
- data/lib/skylight/probes/excon/middleware.rb +65 -0
- data/lib/skylight/probes/net_http.rb +44 -0
- data/lib/skylight/probes/redis.rb +30 -0
- data/lib/skylight/probes/sequel.rb +30 -0
- data/lib/skylight/probes/sinatra.rb +74 -0
- data/lib/skylight/probes/tilt.rb +27 -0
- data/lib/skylight/railtie.rb +122 -0
- data/lib/skylight/sinatra.rb +4 -0
- data/lib/skylight/subscriber.rb +92 -0
- data/lib/skylight/trace.rb +191 -0
- data/lib/skylight/util.rb +16 -0
- data/lib/skylight/util/allocation_free.rb +17 -0
- data/lib/skylight/util/clock.rb +53 -0
- data/lib/skylight/util/gzip.rb +15 -0
- data/lib/skylight/util/hostname.rb +17 -0
- data/lib/skylight/util/http.rb +218 -0
- data/lib/skylight/util/inflector.rb +110 -0
- data/lib/skylight/util/logging.rb +87 -0
- data/lib/skylight/util/multi_io.rb +21 -0
- data/lib/skylight/util/native_ext_fetcher.rb +205 -0
- data/lib/skylight/util/platform.rb +67 -0
- data/lib/skylight/util/ssl.rb +50 -0
- data/lib/skylight/vendor/active_support/notifications.rb +207 -0
- data/lib/skylight/vendor/active_support/notifications/fanout.rb +159 -0
- data/lib/skylight/vendor/active_support/notifications/instrumenter.rb +72 -0
- data/lib/skylight/vendor/active_support/per_thread_registry.rb +52 -0
- data/lib/skylight/vendor/cli/highline.rb +1034 -0
- data/lib/skylight/vendor/cli/highline/color_scheme.rb +134 -0
- data/lib/skylight/vendor/cli/highline/compatibility.rb +16 -0
- data/lib/skylight/vendor/cli/highline/import.rb +41 -0
- data/lib/skylight/vendor/cli/highline/menu.rb +381 -0
- data/lib/skylight/vendor/cli/highline/question.rb +481 -0
- data/lib/skylight/vendor/cli/highline/simulate.rb +48 -0
- data/lib/skylight/vendor/cli/highline/string_extensions.rb +111 -0
- data/lib/skylight/vendor/cli/highline/style.rb +181 -0
- data/lib/skylight/vendor/cli/highline/system_extensions.rb +242 -0
- data/lib/skylight/vendor/cli/thor.rb +473 -0
- data/lib/skylight/vendor/cli/thor/actions.rb +318 -0
- data/lib/skylight/vendor/cli/thor/actions/create_file.rb +105 -0
- data/lib/skylight/vendor/cli/thor/actions/create_link.rb +60 -0
- data/lib/skylight/vendor/cli/thor/actions/directory.rb +119 -0
- data/lib/skylight/vendor/cli/thor/actions/empty_directory.rb +137 -0
- data/lib/skylight/vendor/cli/thor/actions/file_manipulation.rb +314 -0
- data/lib/skylight/vendor/cli/thor/actions/inject_into_file.rb +109 -0
- data/lib/skylight/vendor/cli/thor/base.rb +652 -0
- data/lib/skylight/vendor/cli/thor/command.rb +136 -0
- data/lib/skylight/vendor/cli/thor/core_ext/hash_with_indifferent_access.rb +80 -0
- data/lib/skylight/vendor/cli/thor/core_ext/io_binary_read.rb +12 -0
- data/lib/skylight/vendor/cli/thor/core_ext/ordered_hash.rb +100 -0
- data/lib/skylight/vendor/cli/thor/error.rb +28 -0
- data/lib/skylight/vendor/cli/thor/group.rb +282 -0
- data/lib/skylight/vendor/cli/thor/invocation.rb +172 -0
- data/lib/skylight/vendor/cli/thor/parser.rb +4 -0
- data/lib/skylight/vendor/cli/thor/parser/argument.rb +74 -0
- data/lib/skylight/vendor/cli/thor/parser/arguments.rb +171 -0
- data/lib/skylight/vendor/cli/thor/parser/option.rb +121 -0
- data/lib/skylight/vendor/cli/thor/parser/options.rb +218 -0
- data/lib/skylight/vendor/cli/thor/rake_compat.rb +72 -0
- data/lib/skylight/vendor/cli/thor/runner.rb +322 -0
- data/lib/skylight/vendor/cli/thor/shell.rb +88 -0
- data/lib/skylight/vendor/cli/thor/shell/basic.rb +393 -0
- data/lib/skylight/vendor/cli/thor/shell/color.rb +148 -0
- data/lib/skylight/vendor/cli/thor/shell/html.rb +127 -0
- data/lib/skylight/vendor/cli/thor/util.rb +270 -0
- data/lib/skylight/vendor/cli/thor/version.rb +3 -0
- data/lib/skylight/vendor/thread_safe.rb +126 -0
- data/lib/skylight/vendor/thread_safe/non_concurrent_cache_backend.rb +133 -0
- data/lib/skylight/vendor/thread_safe/synchronized_cache_backend.rb +76 -0
- data/lib/skylight/version.rb +4 -0
- data/lib/skylight/vm/gc.rb +70 -0
- data/lib/sql_lexer.rb +6 -0
- data/lib/sql_lexer/lexer.rb +579 -0
- data/lib/sql_lexer/string_scanner.rb +11 -0
- data/lib/sql_lexer/version.rb +3 -0
- metadata +179 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#ifndef __SKYLIGHT_NATIVE__
|
|
2
|
+
#define __SKYLIGHT_NATIVE__
|
|
3
|
+
|
|
4
|
+
#include <stdint.h>
|
|
5
|
+
|
|
6
|
+
void sky_activate_memprof(void);
|
|
7
|
+
|
|
8
|
+
void sky_deactivate_memprof(void);
|
|
9
|
+
|
|
10
|
+
uint64_t sky_allocation_count(void);
|
|
11
|
+
|
|
12
|
+
uint64_t sky_consume_allocations();
|
|
13
|
+
|
|
14
|
+
void sky_clear_allocation_count(void);
|
|
15
|
+
|
|
16
|
+
int sky_have_memprof(void);
|
|
17
|
+
|
|
18
|
+
#define UNUSED(x) (void)(x)
|
|
19
|
+
|
|
20
|
+
#endif
|
data/lib/skylight.rb
ADDED
data/lib/skylight/api.rb
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
|
|
3
|
+
module Skylight
|
|
4
|
+
# @api private
|
|
5
|
+
class Api
|
|
6
|
+
attr_reader :config, :http
|
|
7
|
+
|
|
8
|
+
class CreateFailed < StandardError
|
|
9
|
+
attr_reader :res
|
|
10
|
+
|
|
11
|
+
def initialize(res)
|
|
12
|
+
@res = res
|
|
13
|
+
super "failed with status #{res.status}"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def errors
|
|
17
|
+
return unless res.respond_to?(:body) && res.body.is_a?(Hash)
|
|
18
|
+
res.body['errors']
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_s
|
|
22
|
+
if errors
|
|
23
|
+
errors.inspect
|
|
24
|
+
elsif res
|
|
25
|
+
"#{res.class.to_s}: #{res.to_s}"
|
|
26
|
+
else
|
|
27
|
+
super
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def initialize(config, service = :auth)
|
|
33
|
+
@config = config
|
|
34
|
+
@http = Util::HTTP.new(config, service)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def authentication
|
|
38
|
+
@http.authentication
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def authentication=(token)
|
|
42
|
+
@http.authentication = token
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def validate_authentication
|
|
46
|
+
url = URI.parse(config[:auth_url])
|
|
47
|
+
|
|
48
|
+
res = @http.get(url.path)
|
|
49
|
+
|
|
50
|
+
case res.status
|
|
51
|
+
when 200...300
|
|
52
|
+
:ok
|
|
53
|
+
when 400...500
|
|
54
|
+
:invalid
|
|
55
|
+
else
|
|
56
|
+
:unknown
|
|
57
|
+
end
|
|
58
|
+
rescue
|
|
59
|
+
:unknown
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def login(email, password)
|
|
63
|
+
res = http.get('/me', 'X-Email' => email, 'X-Password' => password)
|
|
64
|
+
|
|
65
|
+
if res && res.success?
|
|
66
|
+
res.get('me.authentication_token')
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def create_app(name, token=nil)
|
|
71
|
+
params = { app: { name: name } }
|
|
72
|
+
params[:token] = token if token
|
|
73
|
+
res = @http.post('/apps', params)
|
|
74
|
+
raise CreateFailed, res unless res.success?
|
|
75
|
+
res
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
end
|
data/lib/skylight/cli.rb
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
$:.unshift File.expand_path('../vendor/cli', __FILE__)
|
|
2
|
+
|
|
3
|
+
require 'skylight'
|
|
4
|
+
require 'thor'
|
|
5
|
+
require 'yaml'
|
|
6
|
+
require 'highline'
|
|
7
|
+
require 'active_support/inflector'
|
|
8
|
+
|
|
9
|
+
module Skylight
|
|
10
|
+
# @api private
|
|
11
|
+
class CLI < Thor
|
|
12
|
+
|
|
13
|
+
desc "setup TOKEN", "Sets up a new app using the provided token"
|
|
14
|
+
def setup(token=nil)
|
|
15
|
+
if File.exist?(config_path)
|
|
16
|
+
say "Your app is already on Skylight. http://www.skylight.io", :green
|
|
17
|
+
return
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
unless token
|
|
21
|
+
api.authentication = login
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
res = api.create_app(app_name, token)
|
|
25
|
+
|
|
26
|
+
config[:application] = res.get('app.id')
|
|
27
|
+
config[:authentication] = res.get('app.token')
|
|
28
|
+
config.write(config_path)
|
|
29
|
+
|
|
30
|
+
say "Congratulations. Your application is on Skylight! http://www.skylight.io", :green
|
|
31
|
+
say <<-OUT
|
|
32
|
+
|
|
33
|
+
The application was registered for you and we generated a config file
|
|
34
|
+
containing your API token at:
|
|
35
|
+
|
|
36
|
+
#{relative_config_path}
|
|
37
|
+
|
|
38
|
+
The next step is for you to deploy your application to production. The
|
|
39
|
+
easiest way is to just commit the config file to your source control
|
|
40
|
+
repository and deploy from there. You can learn more about the process at:
|
|
41
|
+
|
|
42
|
+
http://docs.skylight.io/getting-started/#deploy
|
|
43
|
+
|
|
44
|
+
If you want to specify the authentication token as an environment variable,
|
|
45
|
+
you should set the `SKYLIGHT_AUTHENTICATION` variable to:
|
|
46
|
+
|
|
47
|
+
#{config[:authentication]}
|
|
48
|
+
|
|
49
|
+
OUT
|
|
50
|
+
rescue Api::CreateFailed => e
|
|
51
|
+
say "Could not create the application", :red
|
|
52
|
+
say e.to_s, :yellow
|
|
53
|
+
rescue Interrupt
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def app_name
|
|
59
|
+
@app_name ||=
|
|
60
|
+
begin
|
|
61
|
+
name = nil
|
|
62
|
+
|
|
63
|
+
if File.exist?("config/application.rb")
|
|
64
|
+
# This looks like a Rails app, lets make sure we have the railtie loaded
|
|
65
|
+
# skylight.rb checks for Rails, but when running the CLI, Skylight loads before Rails does
|
|
66
|
+
begin
|
|
67
|
+
require "skylight/railtie"
|
|
68
|
+
rescue LoadError => e
|
|
69
|
+
error "Unable to load Railtie. Please notify support@skylight.io."
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Get the name in a process so that we don't pollute our environment here
|
|
73
|
+
# This is especially important since users may have things like WebMock that
|
|
74
|
+
# will prevent us from communicating with the Skylight API
|
|
75
|
+
begin
|
|
76
|
+
namefile = Tempfile.new('skylight-app-name')
|
|
77
|
+
# Windows appears to need double quotes for `rails runner`
|
|
78
|
+
`rails runner "File.open('#{namefile.path}', 'w') {|f| f.write(Rails.application.class.name) rescue '' }"`
|
|
79
|
+
name = namefile.read.split("::").first.underscore.titleize
|
|
80
|
+
name = nil if name.empty?
|
|
81
|
+
rescue => e
|
|
82
|
+
if ENV['DEBUG']
|
|
83
|
+
puts e.class.name
|
|
84
|
+
puts e.to_s
|
|
85
|
+
puts e.backtrace.join("\n")
|
|
86
|
+
end
|
|
87
|
+
ensure
|
|
88
|
+
namefile.close
|
|
89
|
+
namefile.unlink
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
unless name
|
|
93
|
+
warn "Unable to determine Rails application name. Using directory name."
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
unless name
|
|
98
|
+
name = File.basename(File.expand_path('.')).titleize
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
name
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def login
|
|
106
|
+
say "Please enter your email and password below or get a token from https://www.skylight.io/app/setup.", :cyan
|
|
107
|
+
|
|
108
|
+
10.times do
|
|
109
|
+
email = highline.ask("Email: ")
|
|
110
|
+
password = highline.ask("Password: ") { |q| q.echo = "*" }
|
|
111
|
+
|
|
112
|
+
if token = api.login(email, password)
|
|
113
|
+
return token
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
say "Sorry. That email and password was invalid. Please try again", :red
|
|
117
|
+
puts
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
say "Could not login", :red
|
|
121
|
+
return
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def relative_config_path
|
|
125
|
+
'config/skylight.yml'
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def config_path
|
|
129
|
+
File.expand_path(relative_config_path)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def api
|
|
133
|
+
@api ||= Api.new(config)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def highline
|
|
137
|
+
@highline ||= HighLine.new
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def config
|
|
141
|
+
# Calling .load checks ENV variables
|
|
142
|
+
@config ||= Config.load
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
end
|
|
146
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
# Ensure the version of AS:N being used is recent enough
|
|
3
|
+
begin
|
|
4
|
+
# Attempt to reference an internal class only present in the new AS::Notifications
|
|
5
|
+
ActiveSupport::Notifications::Fanout::Subscribers
|
|
6
|
+
rescue NameError
|
|
7
|
+
|
|
8
|
+
# The things we do...
|
|
9
|
+
class ::ActiveSupport::Notifications::Fanout
|
|
10
|
+
attr_reader :subscribers
|
|
11
|
+
|
|
12
|
+
class Subscriber
|
|
13
|
+
attr_reader :pattern, :delegate
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
notifier = ActiveSupport::Notifications.notifier
|
|
18
|
+
|
|
19
|
+
# If the class is missing, require our vendored AS::N
|
|
20
|
+
require 'skylight/vendor/active_support/notifications'
|
|
21
|
+
|
|
22
|
+
if notifier.subscribers.respond_to?(:each)
|
|
23
|
+
notifier.subscribers.each do |sub|
|
|
24
|
+
pattern = sub.respond_to?(:pattern) && sub.pattern
|
|
25
|
+
delegate = sub.respond_to?(:delegate) && sub.delegate
|
|
26
|
+
|
|
27
|
+
if pattern && delegate
|
|
28
|
+
ActiveSupport::Notifications.subscribe(pattern, delegate)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
if defined?(ActiveSupport::Notifications::Fanout::Subscribers::Evented)
|
|
36
|
+
# Handle early RCs of rails 4.0
|
|
37
|
+
# @api private
|
|
38
|
+
class ActiveSupport::Notifications::Fanout::Subscribers::Evented
|
|
39
|
+
unless method_defined?(:publish)
|
|
40
|
+
def publish(name, *args)
|
|
41
|
+
if @delegate.respond_to?(:publish)
|
|
42
|
+
@delegate.publish name, *args
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
require 'yaml'
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'thread'
|
|
5
|
+
require 'openssl'
|
|
6
|
+
require 'skylight/util/hostname'
|
|
7
|
+
require 'skylight/util/logging'
|
|
8
|
+
require 'skylight/util/platform'
|
|
9
|
+
require 'skylight/util/ssl'
|
|
10
|
+
|
|
11
|
+
module Skylight
|
|
12
|
+
class Config
|
|
13
|
+
# @api private
|
|
14
|
+
MUTEX = Mutex.new
|
|
15
|
+
|
|
16
|
+
# Map environment variable keys with Skylight configuration keys
|
|
17
|
+
ENV_TO_KEY = {
|
|
18
|
+
# == Authentication ==
|
|
19
|
+
'AUTHENTICATION' => :'authentication',
|
|
20
|
+
|
|
21
|
+
# == Version ==
|
|
22
|
+
'VERSION' => :'version',
|
|
23
|
+
|
|
24
|
+
# == App settings ==
|
|
25
|
+
'ROOT' => :'root',
|
|
26
|
+
'APPLICATION' => :'application',
|
|
27
|
+
'HOSTNAME' => :'hostname',
|
|
28
|
+
'SESSION_TOKEN' => :'session_token',
|
|
29
|
+
|
|
30
|
+
# == Logging ==
|
|
31
|
+
'LOG_FILE' => :'log_file',
|
|
32
|
+
'LOG_LEVEL' => :'log_level',
|
|
33
|
+
'ALERT_LOG_FILE' => :'alert_log_file',
|
|
34
|
+
|
|
35
|
+
# == Proxy ==
|
|
36
|
+
'PROXY_URL' => :'proxy_url',
|
|
37
|
+
|
|
38
|
+
# == Instrumenter ==
|
|
39
|
+
"IGNORED_ENDPOINT" => :'ignored_endpoint',
|
|
40
|
+
|
|
41
|
+
# == Skylight Remote ==
|
|
42
|
+
"AUTH_URL" => :'auth_url',
|
|
43
|
+
"AUTH_HTTP_DEFLATE" => :'auth_http_deflate',
|
|
44
|
+
"AUTH_HTTP_CONNECT_TIMEOUT" => :'auth_http_connect_timeout',
|
|
45
|
+
"AUTH_HTTP_READ_TIMEOUT" => :'auth_http_read_timeout',
|
|
46
|
+
"REPORT_URL" => :'report_url',
|
|
47
|
+
"REPORT_HTTP_DEFLATE" => :'report_http_deflate',
|
|
48
|
+
"REPORT_HTTP_CONNECT_TIMEOUT" => :'report_http_connect_timeout',
|
|
49
|
+
"REPORT_HTTP_READ_TIMEOUT" => :'report_http_read_timeout',
|
|
50
|
+
|
|
51
|
+
# == Native agent settings ==
|
|
52
|
+
#
|
|
53
|
+
"LAZY_START" => :'daemon.lazy_start',
|
|
54
|
+
"DAEMON_EXEC_PATH" => :'daemon.exec_path',
|
|
55
|
+
"DAEMON_LIB_PATH" => :'daemon.lib_path',
|
|
56
|
+
"PIDFILE_PATH" => :'daemon.pidfile_path',
|
|
57
|
+
"SOCKDIR_PATH" => :'daemon.sockdir_path',
|
|
58
|
+
"BATCH_QUEUE_DEPTH" => :'daemon.batch_queue_depth',
|
|
59
|
+
"BATCH_SAMPLE_SIZE" => :'daemon.batch_sample_size',
|
|
60
|
+
"BATCH_FLUSH_INTERVAL" => :'daemon.batch_flush_interval',
|
|
61
|
+
"DAEMON_TICK_INTERVAL" => :'daemon.tick_interval',
|
|
62
|
+
"DAEMON_SANITY_CHECK_INTERVAL" => :'daemon.sanity_check_interval',
|
|
63
|
+
"DAEMON_INACTIVITY_TIMEOUT" => :'daemon.inactivity_timeout',
|
|
64
|
+
"CLIENT_MAX_TRIES" => :'daemon.max_connect_tries',
|
|
65
|
+
"CLIENT_CONN_TRY_WIN" => :'daemon.connect_try_window',
|
|
66
|
+
"MAX_PRESPAWN_JITTER" => :'daemon.max_prespawn_jitter',
|
|
67
|
+
"DAEMON_WAIT_TIMEOUT" => :'daemon.wait_timeout',
|
|
68
|
+
"CLIENT_CHECK_INTERVAL" => :'daemon.client_check_interval',
|
|
69
|
+
"CLIENT_QUEUE_DEPTH" => :'daemon.client_queue_depth',
|
|
70
|
+
"CLIENT_WRITE_TIMEOUT" => :'daemon.client_write_timeout',
|
|
71
|
+
"SSL_CERT_PATH" => :'daemon.ssl_cert_path',
|
|
72
|
+
"SSL_CERT_DIR" => :'daemon.ssl_cert_dir',
|
|
73
|
+
|
|
74
|
+
# == Legacy env vars ==
|
|
75
|
+
#
|
|
76
|
+
'AGENT_LOCKFILE' => :'agent.lockfile',
|
|
77
|
+
'AGENT_SOCKFILE_PATH' => :'agent.sockfile_path',
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
# Default values for Skylight configuration keys
|
|
81
|
+
DEFAULTS = {
|
|
82
|
+
:'version' => VERSION,
|
|
83
|
+
:'auth_url' => 'https://auth.skylight.io/agent',
|
|
84
|
+
:'daemon.lazy_start' => true,
|
|
85
|
+
:'daemon.ssl_cert_path' => Util::SSL.ca_cert_file_or_default,
|
|
86
|
+
:'daemon.ssl_cert_dir' => Util::SSL.ca_cert_dir,
|
|
87
|
+
|
|
88
|
+
# == Legacy ==
|
|
89
|
+
:'log_file' => '-'.freeze,
|
|
90
|
+
:'log_level' => 'INFO'.freeze,
|
|
91
|
+
:'alert_log_file' => '-'.freeze,
|
|
92
|
+
:'hostname' => Util::Hostname.default_hostname,
|
|
93
|
+
:'agent.keepalive' => 60,
|
|
94
|
+
:'agent.interval' => 5,
|
|
95
|
+
:'agent.sample' => 200,
|
|
96
|
+
:'agent.max_memory' => 256, # MB
|
|
97
|
+
:'report.host' => 'agent.skylight.io'.freeze,
|
|
98
|
+
:'report.port' => 443,
|
|
99
|
+
:'report.ssl' => true,
|
|
100
|
+
:'report.deflate' => true,
|
|
101
|
+
:'accounts.host' => 'www.skylight.io'.freeze,
|
|
102
|
+
:'accounts.port' => 443,
|
|
103
|
+
:'accounts.ssl' => true,
|
|
104
|
+
:'accounts.deflate' => false,
|
|
105
|
+
:'me.credentials_path' => '~/.skylight',
|
|
106
|
+
:'metrics.report_interval' => 60
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if Skylight.native?
|
|
110
|
+
native_path = Skylight.libskylight_path
|
|
111
|
+
|
|
112
|
+
DEFAULTS[:'daemon.lib_path'] = native_path
|
|
113
|
+
DEFAULTS[:'daemon.exec_path'] = File.join(native_path, 'skylightd')
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
DEFAULTS.freeze
|
|
117
|
+
|
|
118
|
+
REQUIRED = {
|
|
119
|
+
:'authentication' => "authentication token",
|
|
120
|
+
:'hostname' => "server hostname",
|
|
121
|
+
:'report.host' => "skylight remote host",
|
|
122
|
+
:'report.port' => "skylight remote port" }
|
|
123
|
+
|
|
124
|
+
ALWAYS_INCLUDE_IN_ENV = [
|
|
125
|
+
:version,
|
|
126
|
+
:'daemon.lazy_start',
|
|
127
|
+
:'daemon.lib_path',
|
|
128
|
+
:'daemon.exec_path',
|
|
129
|
+
:'daemon.ssl_cert_dir',
|
|
130
|
+
:'daemon.ssl_cert_path' ]
|
|
131
|
+
|
|
132
|
+
# Maps legacy config keys to new config keys
|
|
133
|
+
LEGACY = {
|
|
134
|
+
:'agent.sockfile_path' => :'daemon.sockdir_path',
|
|
135
|
+
:'agent.pidfile_path' => :'agent.lockfile',
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
VALIDATORS = {
|
|
139
|
+
:'agent.interval' => [lambda { |v, c| Integer === v && v > 0 }, "must be an integer greater than 0"]
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
# @api private
|
|
143
|
+
attr_reader :environment
|
|
144
|
+
|
|
145
|
+
# @api private
|
|
146
|
+
def initialize(*args)
|
|
147
|
+
attrs = {}
|
|
148
|
+
|
|
149
|
+
if Hash === args.last
|
|
150
|
+
attrs = args.pop.dup
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
@values = {}
|
|
154
|
+
@priority = {}
|
|
155
|
+
@regexp = nil
|
|
156
|
+
|
|
157
|
+
p = attrs.delete(:priority)
|
|
158
|
+
|
|
159
|
+
if @environment = args[0]
|
|
160
|
+
@regexp = /^#{Regexp.escape(@environment)}\.(.+)$/
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
attrs.each do |k, v|
|
|
164
|
+
self[k] = v
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
if p
|
|
168
|
+
p.each do |k, v|
|
|
169
|
+
@priority[Config.remap_key(k)] = v
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def self.load(opts = {}, env = ENV)
|
|
175
|
+
attrs = {}
|
|
176
|
+
version = nil
|
|
177
|
+
|
|
178
|
+
path = opts.delete(:file)
|
|
179
|
+
environment = opts.delete(:environment)
|
|
180
|
+
|
|
181
|
+
if path
|
|
182
|
+
error = nil
|
|
183
|
+
begin
|
|
184
|
+
attrs = YAML.load_file(path)
|
|
185
|
+
error = "empty file" unless attrs
|
|
186
|
+
error = "invalid format" if attrs && !attrs.is_a?(Hash)
|
|
187
|
+
rescue Exception => e
|
|
188
|
+
error = e.message
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
raise ConfigError, "could not load config file; msg=#{error}" if error
|
|
192
|
+
|
|
193
|
+
version = File.mtime(path).to_i
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
if env
|
|
197
|
+
attrs[:priority] = remap_env(env)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
config = new(environment, attrs)
|
|
201
|
+
|
|
202
|
+
opts.each do |k, v|
|
|
203
|
+
config[k] = v
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
config
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def self.remap_key(key)
|
|
210
|
+
key = key.to_sym
|
|
211
|
+
LEGACY[key] || key
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# @api private
|
|
215
|
+
def self.remap_env(env)
|
|
216
|
+
ret = {}
|
|
217
|
+
|
|
218
|
+
return ret unless env
|
|
219
|
+
|
|
220
|
+
ret[:proxy_url] = detect_proxy_url(env)
|
|
221
|
+
|
|
222
|
+
env.each do |k, val|
|
|
223
|
+
# Support deprecated SK_ key prefix
|
|
224
|
+
next unless k =~ /^(?:SK|SKYLIGHT)_(.+)$/
|
|
225
|
+
|
|
226
|
+
if key = ENV_TO_KEY[$1]
|
|
227
|
+
ret[key] =
|
|
228
|
+
case val
|
|
229
|
+
when /^false$/i then false
|
|
230
|
+
when /^true$/i then true
|
|
231
|
+
when /^(nil|null)$/i then nil
|
|
232
|
+
when /^\d+$/ then val.to_i
|
|
233
|
+
when /^\d+\.\d+$/ then val.to_f
|
|
234
|
+
else val
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
ret
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def self.detect_proxy_url(env)
|
|
243
|
+
if u = env['HTTP_PROXY'] || env['http_proxy']
|
|
244
|
+
u = "http://#{u}" unless u =~ %r[://]
|
|
245
|
+
u
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# @api private
|
|
250
|
+
def skip_validation?
|
|
251
|
+
!!get(:skip_validation)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# @api private
|
|
255
|
+
def validate!
|
|
256
|
+
return true if skip_validation?
|
|
257
|
+
|
|
258
|
+
REQUIRED.each do |k, v|
|
|
259
|
+
unless get(k)
|
|
260
|
+
raise ConfigError, "#{v} required"
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
sockdir_path = self[:'daemon.sockdir_path'] || File.expand_path('.')
|
|
265
|
+
pidfile_path = self[:'daemon.pidfile_path'] || File.expand_path('skylight.pid', sockdir_path)
|
|
266
|
+
|
|
267
|
+
check_permissions(pidfile_path, sockdir_path)
|
|
268
|
+
|
|
269
|
+
true
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def check_permissions(pidfile, sockdir_path)
|
|
273
|
+
pidfile_root = File.dirname(pidfile)
|
|
274
|
+
|
|
275
|
+
FileUtils.mkdir_p pidfile_root
|
|
276
|
+
FileUtils.mkdir_p sockdir_path
|
|
277
|
+
|
|
278
|
+
if File.exist?(pidfile)
|
|
279
|
+
if !FileTest.writable?(pidfile)
|
|
280
|
+
raise ConfigError, "File `#{pidfile}` not writable. Please set daemon.pidfile_path or daemon.sockdir_path in your config to a writable path"
|
|
281
|
+
end
|
|
282
|
+
else
|
|
283
|
+
if !FileTest.writable?(pidfile_root)
|
|
284
|
+
raise ConfigError, "Directory `#{pidfile_root}` not writable. Please set daemon.pidfile_path or daemon.sockdir_path in your config to a writable path"
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
unless FileTest.writable?(sockdir_path)
|
|
289
|
+
raise ConfigError, "Directory `#{sockdir_path}` not writable. Please set daemon.sockdir_path in your config to a writable path"
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def key?(key)
|
|
294
|
+
key = Config.remap_key(key)
|
|
295
|
+
@priority.key?(key) || @values.key?(key)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def get(key, default = nil, &blk)
|
|
299
|
+
key = Config.remap_key(key)
|
|
300
|
+
|
|
301
|
+
return @priority[key] if @priority.key?(key)
|
|
302
|
+
return @values[key] if @values.key?(key)
|
|
303
|
+
return DEFAULTS[key] if DEFAULTS.key?(key)
|
|
304
|
+
|
|
305
|
+
if default
|
|
306
|
+
return default
|
|
307
|
+
elsif blk
|
|
308
|
+
return blk.call(key)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
nil
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
alias [] get
|
|
315
|
+
|
|
316
|
+
def set(key, val, scope = nil)
|
|
317
|
+
if scope
|
|
318
|
+
key = [scope, key].join('.')
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
if Hash === val
|
|
322
|
+
val.each do |k, v|
|
|
323
|
+
set(k, v, key)
|
|
324
|
+
end
|
|
325
|
+
else
|
|
326
|
+
k = Config.remap_key(key)
|
|
327
|
+
|
|
328
|
+
if validator = VALIDATORS[k]
|
|
329
|
+
blk, msg = validator
|
|
330
|
+
|
|
331
|
+
unless blk.call(val, self)
|
|
332
|
+
error_msg = "invalid value for #{k} (#{val})"
|
|
333
|
+
error_msg << ", #{msg}" if msg
|
|
334
|
+
raise ConfigError, error_msg
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
if @regexp && k =~ @regexp
|
|
339
|
+
@priority[$1.to_sym] = val
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
@values[k] = val
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
alias []= set
|
|
347
|
+
|
|
348
|
+
def duration_ms(key, default = nil)
|
|
349
|
+
if (v = self[key]) && v.to_s =~ /^\s*(\d+)(s|sec|ms|micros|nanos)?\s*$/
|
|
350
|
+
v = $1.to_i
|
|
351
|
+
case $2
|
|
352
|
+
when "ms"
|
|
353
|
+
v
|
|
354
|
+
when "micros"
|
|
355
|
+
v / 1_000
|
|
356
|
+
when "nanos"
|
|
357
|
+
v / 1_000_000
|
|
358
|
+
else # "s", "sec", nil
|
|
359
|
+
v * 1000
|
|
360
|
+
end
|
|
361
|
+
else
|
|
362
|
+
default
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def to_env
|
|
367
|
+
ret = []
|
|
368
|
+
|
|
369
|
+
ENV_TO_KEY.each do |k, v|
|
|
370
|
+
next if LEGACY[v]
|
|
371
|
+
c = get(v)
|
|
372
|
+
# Always need to pass daemon lib_path config even when default
|
|
373
|
+
if c != DEFAULTS[v] || ALWAYS_INCLUDE_IN_ENV.include?(v)
|
|
374
|
+
ret << "SKYLIGHT_#{k}" << cast_for_env(c) if c
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
ret << "SKYLIGHT_VALIDATE_AUTHENTICATION"
|
|
379
|
+
ret << "false"
|
|
380
|
+
|
|
381
|
+
ret
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
def write(path)
|
|
385
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
386
|
+
|
|
387
|
+
File.open(path, 'w') do |f|
|
|
388
|
+
f.puts <<-YAML
|
|
389
|
+
---
|
|
390
|
+
# The authentication token for the application.
|
|
391
|
+
authentication: #{self[:authentication]}
|
|
392
|
+
YAML
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
#
|
|
397
|
+
#
|
|
398
|
+
# ===== Helpers =====
|
|
399
|
+
#
|
|
400
|
+
#
|
|
401
|
+
|
|
402
|
+
# @api private
|
|
403
|
+
def gc
|
|
404
|
+
@gc ||= GC.new(self, get('gc.profiler', VM::GC.new))
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
# @api private
|
|
408
|
+
def ignore_token?
|
|
409
|
+
get('test.ignore_token')
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
# @api private
|
|
413
|
+
def ignored_endpoints
|
|
414
|
+
@ignored_endpoints ||=
|
|
415
|
+
begin
|
|
416
|
+
val = Array(get(:'ignored_endpoint'))
|
|
417
|
+
val.concat(Array(get(:'ignored_endpoints')))
|
|
418
|
+
val
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
def root
|
|
423
|
+
self[:root] || Dir.pwd
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
def logger
|
|
427
|
+
@logger ||=
|
|
428
|
+
MUTEX.synchronize do
|
|
429
|
+
load_logger
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
def logger=(logger)
|
|
434
|
+
@logger = logger
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
def alert_logger
|
|
438
|
+
@alert_logger ||=
|
|
439
|
+
begin
|
|
440
|
+
MUTEX.synchronize do
|
|
441
|
+
unless l = @alert_logger
|
|
442
|
+
out = get(:'alert_log_file')
|
|
443
|
+
|
|
444
|
+
if out == '-'
|
|
445
|
+
out = Util::AlertLogger.new(load_logger)
|
|
446
|
+
elsif !(IO === out)
|
|
447
|
+
out = File.expand_path(out, root)
|
|
448
|
+
FileUtils.mkdir_p(File.dirname(out))
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
l = Logger.new(out)
|
|
452
|
+
l.level = Logger::DEBUG
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
l
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
def alert_logger=(logger)
|
|
461
|
+
@alert_logger = logger
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
private
|
|
465
|
+
|
|
466
|
+
def load_logger
|
|
467
|
+
unless l = @logger
|
|
468
|
+
out = get(:'log_file')
|
|
469
|
+
out = STDOUT if out == '-'
|
|
470
|
+
|
|
471
|
+
unless IO === out
|
|
472
|
+
out = File.expand_path(out, root)
|
|
473
|
+
FileUtils.mkdir_p(File.dirname(out))
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
l = Logger.new(out)
|
|
477
|
+
l.level =
|
|
478
|
+
case get(:'log_level')
|
|
479
|
+
when /^debug$/i then Logger::DEBUG
|
|
480
|
+
when /^info$/i then Logger::INFO
|
|
481
|
+
when /^warn$/i then Logger::WARN
|
|
482
|
+
when /^error$/i then Logger::ERROR
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
l
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
def cast_for_env(v)
|
|
490
|
+
case v
|
|
491
|
+
when true then 'true'
|
|
492
|
+
when false then 'false'
|
|
493
|
+
when nil then 'nil'
|
|
494
|
+
else v.to_s
|
|
495
|
+
end
|
|
496
|
+
end
|
|
497
|
+
end
|
|
498
|
+
end
|