skylight 4.3.2 → 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 +399 -336
- data/CLA.md +1 -1
- data/CONTRIBUTING.md +2 -8
- data/LICENSE.md +7 -17
- data/README.md +1 -1
- data/ext/extconf.rb +45 -56
- data/ext/libskylight.yml +10 -6
- data/ext/skylight_native.c +22 -99
- data/lib/skylight.rb +201 -14
- data/lib/skylight/api.rb +32 -21
- data/lib/skylight/cli.rb +48 -46
- data/lib/skylight/cli/doctor.rb +62 -63
- data/lib/skylight/cli/helpers.rb +19 -19
- data/lib/skylight/cli/merger.rb +142 -138
- data/lib/skylight/config.rb +634 -199
- data/lib/skylight/deprecation.rb +17 -0
- data/lib/skylight/errors.rb +23 -9
- data/lib/skylight/extensions.rb +95 -0
- data/lib/skylight/extensions/source_location.rb +291 -0
- data/lib/skylight/formatters/http.rb +18 -0
- data/lib/skylight/gc.rb +99 -0
- data/lib/skylight/helpers.rb +81 -36
- data/lib/skylight/instrumenter.rb +336 -18
- data/lib/skylight/middleware.rb +134 -1
- data/lib/skylight/native.rb +60 -12
- data/lib/skylight/native_ext_fetcher.rb +13 -14
- data/lib/skylight/normalizers.rb +157 -0
- data/lib/skylight/normalizers/action_controller/process_action.rb +68 -0
- data/lib/skylight/normalizers/action_controller/send_file.rb +51 -0
- data/lib/skylight/normalizers/action_dispatch/process_middleware.rb +22 -0
- data/lib/skylight/normalizers/action_dispatch/route_set.rb +27 -0
- data/lib/skylight/normalizers/action_view/render_collection.rb +24 -0
- data/lib/skylight/normalizers/action_view/render_layout.rb +25 -0
- data/lib/skylight/normalizers/action_view/render_partial.rb +23 -0
- data/lib/skylight/normalizers/action_view/render_template.rb +23 -0
- data/lib/skylight/normalizers/active_job/perform.rb +90 -0
- data/lib/skylight/normalizers/active_model_serializers/render.rb +32 -0
- data/lib/skylight/normalizers/active_record/instantiation.rb +16 -0
- data/lib/skylight/normalizers/active_record/sql.rb +12 -0
- data/lib/skylight/normalizers/active_storage.rb +28 -0
- data/lib/skylight/normalizers/active_support/cache.rb +11 -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/coach/handler_finish.rb +44 -0
- data/lib/skylight/normalizers/coach/middleware_finish.rb +33 -0
- data/lib/skylight/normalizers/couch_potato/query.rb +20 -0
- data/lib/skylight/normalizers/data_mapper/sql.rb +12 -0
- data/lib/skylight/normalizers/default.rb +24 -0
- data/lib/skylight/normalizers/elasticsearch/request.rb +20 -0
- data/lib/skylight/normalizers/faraday/request.rb +38 -0
- data/lib/skylight/normalizers/grape/endpoint.rb +28 -0
- data/lib/skylight/normalizers/grape/endpoint_render.rb +25 -0
- data/lib/skylight/normalizers/grape/endpoint_run.rb +39 -0
- data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +20 -0
- data/lib/skylight/normalizers/grape/format_response.rb +20 -0
- data/lib/skylight/normalizers/graphiti/render.rb +22 -0
- data/lib/skylight/normalizers/graphiti/resolve.rb +31 -0
- data/lib/skylight/normalizers/graphql/base.rb +127 -0
- data/lib/skylight/normalizers/render.rb +79 -0
- data/lib/skylight/normalizers/sequel/sql.rb +12 -0
- data/lib/skylight/normalizers/shrine.rb +32 -0
- data/lib/skylight/normalizers/sql.rb +45 -0
- data/lib/skylight/probes.rb +173 -0
- data/lib/skylight/probes/action_controller.rb +52 -0
- data/lib/skylight/probes/action_dispatch.rb +2 -0
- data/lib/skylight/probes/action_dispatch/request_id.rb +33 -0
- data/lib/skylight/probes/action_dispatch/routing/route_set.rb +30 -0
- data/lib/skylight/probes/action_view.rb +42 -0
- data/lib/skylight/probes/active_job.rb +27 -0
- data/lib/skylight/probes/active_job_enqueue.rb +35 -0
- data/lib/skylight/probes/active_model_serializers.rb +50 -0
- data/lib/skylight/probes/delayed_job.rb +144 -0
- data/lib/skylight/probes/elasticsearch.rb +36 -0
- data/lib/skylight/probes/excon.rb +25 -0
- data/lib/skylight/probes/excon/middleware.rb +65 -0
- data/lib/skylight/probes/faraday.rb +23 -0
- data/lib/skylight/probes/graphql.rb +38 -0
- data/lib/skylight/probes/httpclient.rb +44 -0
- data/lib/skylight/probes/middleware.rb +135 -0
- data/lib/skylight/probes/mongo.rb +156 -0
- data/lib/skylight/probes/mongoid.rb +13 -0
- data/lib/skylight/probes/net_http.rb +54 -0
- data/lib/skylight/probes/redis.rb +51 -0
- data/lib/skylight/probes/sequel.rb +29 -0
- data/lib/skylight/probes/sinatra.rb +66 -0
- data/lib/skylight/probes/sinatra_add_middleware.rb +10 -10
- data/lib/skylight/probes/tilt.rb +25 -0
- data/lib/skylight/railtie.rb +157 -27
- data/lib/skylight/sidekiq.rb +47 -0
- data/lib/skylight/subscriber.rb +108 -0
- data/lib/skylight/test.rb +151 -0
- data/lib/skylight/trace.rb +325 -22
- data/lib/skylight/user_config.rb +58 -0
- data/lib/skylight/util.rb +12 -0
- data/lib/skylight/util/allocation_free.rb +26 -0
- data/lib/skylight/util/clock.rb +57 -0
- data/lib/skylight/util/component.rb +22 -22
- data/lib/skylight/util/deploy.rb +16 -21
- data/lib/skylight/util/gzip.rb +20 -0
- data/lib/skylight/util/http.rb +106 -113
- data/lib/skylight/util/instrumenter_method.rb +26 -0
- data/lib/skylight/util/logging.rb +136 -0
- data/lib/skylight/util/lru_cache.rb +36 -0
- data/lib/skylight/util/platform.rb +1 -5
- data/lib/skylight/util/ssl.rb +1 -25
- data/lib/skylight/vendor/cli/thor/rake_compat.rb +1 -1
- data/lib/skylight/version.rb +5 -1
- data/lib/skylight/vm/gc.rb +60 -0
- metadata +126 -13
data/lib/skylight/config.rb
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
require "openssl"
|
|
2
|
+
require "yaml"
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "erb"
|
|
5
|
+
require "json"
|
|
6
|
+
require "skylight/util/logging"
|
|
7
|
+
require "skylight/util/proxy"
|
|
8
|
+
require "skylight/errors"
|
|
2
9
|
require "skylight/util/component"
|
|
3
10
|
require "skylight/util/deploy"
|
|
4
11
|
require "skylight/util/platform"
|
|
@@ -6,178 +13,323 @@ require "skylight/util/hostname"
|
|
|
6
13
|
require "skylight/util/ssl"
|
|
7
14
|
|
|
8
15
|
module Skylight
|
|
9
|
-
class Config
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
16
|
+
class Config
|
|
17
|
+
include Util::Logging
|
|
18
|
+
|
|
19
|
+
# @api private
|
|
20
|
+
MUTEX = Mutex.new
|
|
21
|
+
|
|
22
|
+
# Map environment variable keys with Skylight configuration keys
|
|
23
|
+
ENV_TO_KEY = {
|
|
24
|
+
# == Authentication ==
|
|
25
|
+
-"AUTHENTICATION" => :authentication,
|
|
26
|
+
# == App settings ==
|
|
27
|
+
-"ROOT" => :root,
|
|
28
|
+
-"HOSTNAME" => :hostname,
|
|
29
|
+
-"SESSION_TOKEN" => :session_token,
|
|
30
|
+
# == Component settings ==
|
|
31
|
+
-"ENV" => :env,
|
|
32
|
+
-"COMPONENT" => :component,
|
|
33
|
+
-"REPORT_RAILS_ENV" => :report_rails_env,
|
|
34
|
+
# == Deploy settings ==
|
|
35
|
+
-"DEPLOY_ID" => :'deploy.id',
|
|
36
|
+
-"DEPLOY_GIT_SHA" => :'deploy.git_sha',
|
|
37
|
+
-"DEPLOY_DESCRIPTION" => :'deploy.description',
|
|
38
|
+
# == Logging ==
|
|
39
|
+
-"LOG_FILE" => :log_file,
|
|
40
|
+
-"LOG_LEVEL" => :log_level,
|
|
41
|
+
-"ALERT_LOG_FILE" => :alert_log_file,
|
|
42
|
+
-"NATIVE_LOG_FILE" => :native_log_file,
|
|
43
|
+
-"NATIVE_LOG_LEVEL" => :native_log_level,
|
|
44
|
+
-"LOG_SQL_PARSE_ERRORS" => :log_sql_parse_errors,
|
|
45
|
+
# == Proxy ==
|
|
46
|
+
-"PROXY_URL" => :proxy_url,
|
|
47
|
+
# == Instrumenter ==
|
|
48
|
+
-"ENABLE_SEGMENTS" => :enable_segments,
|
|
49
|
+
-"ENABLE_SIDEKIQ" => :enable_sidekiq,
|
|
50
|
+
-"IGNORED_ENDPOINT" => :ignored_endpoint,
|
|
51
|
+
-"IGNORED_ENDPOINTS" => :ignored_endpoints,
|
|
52
|
+
-"SINATRA_ROUTE_PREFIXES" => :sinatra_route_prefixes,
|
|
53
|
+
-"ENABLE_SOURCE_LOCATIONS" => :enable_source_locations,
|
|
54
|
+
# == Max Span Handling ==
|
|
55
|
+
-"REPORT_MAX_SPANS_EXCEEDED" => :report_max_spans_exceeded,
|
|
56
|
+
-"PRUNE_LARGE_TRACES" => :prune_large_traces,
|
|
57
|
+
# == Skylight Remote ==
|
|
58
|
+
-"AUTH_URL" => :auth_url,
|
|
59
|
+
-"APP_CREATE_URL" => :app_create_url,
|
|
60
|
+
-"MERGES_URL" => :merges_url,
|
|
61
|
+
-"VALIDATION_URL" => :validation_url,
|
|
62
|
+
-"AUTH_HTTP_DEFLATE" => :auth_http_deflate,
|
|
63
|
+
-"AUTH_HTTP_CONNECT_TIMEOUT" => :auth_http_connect_timeout,
|
|
64
|
+
-"AUTH_HTTP_READ_TIMEOUT" => :auth_http_read_timeout,
|
|
65
|
+
-"REPORT_URL" => :report_url,
|
|
66
|
+
-"REPORT_HTTP_DEFLATE" => :report_http_deflate,
|
|
67
|
+
-"REPORT_HTTP_CONNECT_TIMEOUT" => :report_http_connect_timeout,
|
|
68
|
+
-"REPORT_HTTP_READ_TIMEOUT" => :report_http_read_timeout,
|
|
69
|
+
-"REPORT_HTTP_DISABLED" => :report_http_disabled,
|
|
70
|
+
# == Native agent settings ==
|
|
71
|
+
#
|
|
72
|
+
-"LAZY_START" => :'daemon.lazy_start',
|
|
73
|
+
-"DAEMON_EXEC_PATH" => :'daemon.exec_path',
|
|
74
|
+
-"DAEMON_LIB_PATH" => :'daemon.lib_path',
|
|
75
|
+
-"PIDFILE_PATH" => :'daemon.pidfile_path',
|
|
76
|
+
-"SOCKDIR_PATH" => :'daemon.sockdir_path',
|
|
77
|
+
-"BATCH_QUEUE_DEPTH" => :'daemon.batch_queue_depth',
|
|
78
|
+
-"BATCH_SAMPLE_SIZE" => :'daemon.batch_sample_size',
|
|
79
|
+
-"BATCH_FLUSH_INTERVAL" => :'daemon.batch_flush_interval',
|
|
80
|
+
-"DAEMON_TICK_INTERVAL" => :'daemon.tick_interval',
|
|
81
|
+
-"DAEMON_LOCK_CHECK_INTERVAL" => :'daemon.lock_check_interval',
|
|
82
|
+
-"DAEMON_INACTIVITY_TIMEOUT" => :'daemon.inactivity_timeout',
|
|
83
|
+
-"CLIENT_MAX_TRIES" => :'daemon.max_connect_tries',
|
|
84
|
+
-"CLIENT_CONN_TRY_WIN" => :'daemon.connect_try_window',
|
|
85
|
+
-"MAX_PRESPAWN_JITTER" => :'daemon.max_prespawn_jitter',
|
|
86
|
+
-"DAEMON_WAIT_TIMEOUT" => :'daemon.wait_timeout',
|
|
87
|
+
-"CLIENT_CHECK_INTERVAL" => :'daemon.client_check_interval',
|
|
88
|
+
-"CLIENT_QUEUE_DEPTH" => :'daemon.client_queue_depth',
|
|
89
|
+
-"CLIENT_WRITE_TIMEOUT" => :'daemon.client_write_timeout',
|
|
90
|
+
-"SSL_CERT_PATH" => :'daemon.ssl_cert_path',
|
|
91
|
+
-"ENABLE_TCP" => :'daemon.enable_tcp',
|
|
92
|
+
-"TCP_PORT" => :'daemon.tcp_port',
|
|
93
|
+
# == Legacy env vars ==
|
|
94
|
+
#
|
|
95
|
+
-"AGENT_LOCKFILE" => :'agent.lockfile',
|
|
96
|
+
-"AGENT_SOCKFILE_PATH" => :'agent.sockfile_path',
|
|
97
|
+
# == User config settings ==
|
|
98
|
+
-"USER_CONFIG_PATH" => :user_config_path,
|
|
99
|
+
# == Heroku settings ==
|
|
100
|
+
-"HEROKU_DYNO_INFO_PATH" => :'heroku.dyno_info_path',
|
|
101
|
+
# == Source Location ==
|
|
102
|
+
-"SOURCE_LOCATION_IGNORED_GEMS" => :source_location_ignored_gems,
|
|
103
|
+
-"SOURCE_LOCATION_CACHE_SIZE" => :source_location_cache_size
|
|
104
|
+
}.freeze
|
|
105
|
+
|
|
106
|
+
KEY_TO_NATIVE_ENV = {
|
|
107
|
+
# We use different log files for native and Ruby, but the native code doesn't know this
|
|
108
|
+
native_log_file: "LOG_FILE",
|
|
109
|
+
native_log_level: "LOG_LEVEL"
|
|
110
|
+
}.freeze
|
|
111
|
+
|
|
112
|
+
SERVER_VALIDATE = %i[].freeze
|
|
113
|
+
|
|
114
|
+
DEFAULT_IGNORED_SOURCE_LOCATION_GEMS = [-"skylight", -"activesupport", -"activerecord"].freeze
|
|
81
115
|
|
|
82
116
|
# Default values for Skylight configuration keys
|
|
83
117
|
def self.default_values
|
|
84
|
-
@default_values ||=
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
118
|
+
@default_values ||=
|
|
119
|
+
begin
|
|
120
|
+
ret = {
|
|
121
|
+
# URLs
|
|
122
|
+
auth_url: -"https://auth.skylight.io/agent",
|
|
123
|
+
app_create_url: -"https://www.skylight.io/apps",
|
|
124
|
+
merges_url: -"https://www.skylight.io/merges",
|
|
125
|
+
validation_url: -"https://auth.skylight.io/agent/config",
|
|
126
|
+
# Logging
|
|
127
|
+
log_file: -"-",
|
|
128
|
+
log_level: -"INFO",
|
|
129
|
+
alert_log_file: -"-",
|
|
130
|
+
log_sql_parse_errors: true,
|
|
131
|
+
native_log_level: -"warn",
|
|
132
|
+
# Features
|
|
133
|
+
enable_segments: true,
|
|
134
|
+
enable_sidekiq: false,
|
|
135
|
+
sinatra_route_prefixes: false,
|
|
136
|
+
enable_source_locations: true,
|
|
137
|
+
# Deploys
|
|
138
|
+
'heroku.dyno_info_path': -"/etc/heroku/dyno",
|
|
139
|
+
report_rails_env: true,
|
|
140
|
+
# Daemon
|
|
141
|
+
'daemon.lazy_start': true,
|
|
142
|
+
hostname: Util::Hostname.default_hostname,
|
|
143
|
+
report_max_spans_exceeded: false,
|
|
144
|
+
prune_large_traces: true
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
ret[:'daemon.ssl_cert_path'] = Util::SSL.ca_cert_file_or_default unless Util::Platform::OS == -"darwin"
|
|
148
|
+
|
|
149
|
+
if Skylight.native?
|
|
150
|
+
native_path = Skylight.libskylight_path
|
|
151
|
+
|
|
152
|
+
ret[:'daemon.lib_path'] = native_path
|
|
153
|
+
ret[:'daemon.exec_path'] = File.join(native_path, "skylightd")
|
|
154
|
+
end
|
|
104
155
|
|
|
105
|
-
ret
|
|
106
|
-
ret[:'daemon.exec_path'] = File.join(native_path, "skylightd")
|
|
156
|
+
ret
|
|
107
157
|
end
|
|
108
|
-
|
|
109
|
-
ret
|
|
110
|
-
end
|
|
111
158
|
end
|
|
112
159
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
)
|
|
120
|
-
end
|
|
160
|
+
REQUIRED_KEYS = {
|
|
161
|
+
authentication: "authentication token",
|
|
162
|
+
hostname: "server hostname",
|
|
163
|
+
auth_url: "authentication url",
|
|
164
|
+
validation_url: "config validation url"
|
|
165
|
+
}.freeze
|
|
121
166
|
|
|
122
167
|
def self.native_env_keys
|
|
123
|
-
@native_env_keys ||=
|
|
124
|
-
|
|
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
|
-
|
|
168
|
+
@native_env_keys ||=
|
|
169
|
+
%i[
|
|
170
|
+
native_log_level
|
|
171
|
+
native_log_file
|
|
172
|
+
log_sql_parse_errors
|
|
173
|
+
version
|
|
174
|
+
root
|
|
175
|
+
proxy_url
|
|
176
|
+
hostname
|
|
177
|
+
session_token
|
|
178
|
+
auth_url
|
|
179
|
+
auth_http_deflate
|
|
180
|
+
auth_http_connect_timeout
|
|
181
|
+
auth_http_read_timeout
|
|
182
|
+
report_url
|
|
183
|
+
report_http_deflate
|
|
184
|
+
report_http_connect_timeout
|
|
185
|
+
report_http_read_timeout
|
|
186
|
+
report_http_disabled
|
|
187
|
+
daemon.lazy_start
|
|
188
|
+
daemon.exec_path
|
|
189
|
+
daemon.lib_path
|
|
190
|
+
daemon.pidfile_path
|
|
191
|
+
daemon.sockdir_path
|
|
192
|
+
daemon.batch_queue_depth
|
|
193
|
+
daemon.batch_sample_size
|
|
194
|
+
daemon.batch_flush_interval
|
|
195
|
+
daemon.tick_interval
|
|
196
|
+
daemon.lock_check_interval
|
|
197
|
+
daemon.inactivity_timeout
|
|
198
|
+
daemon.max_connect_tries
|
|
199
|
+
daemon.connect_try_window
|
|
200
|
+
daemon.max_prespawn_jitter
|
|
201
|
+
daemon.wait_timeout
|
|
202
|
+
daemon.client_check_interval
|
|
203
|
+
daemon.client_queue_depth
|
|
204
|
+
daemon.client_write_timeout
|
|
205
|
+
daemon.ssl_cert_path
|
|
206
|
+
daemon.ssl_cert_dir
|
|
207
|
+
daemon.enable_tcp
|
|
208
|
+
daemon.tcp_port
|
|
209
|
+
]
|
|
158
210
|
end
|
|
159
211
|
|
|
212
|
+
# Maps legacy config keys to new config keys
|
|
160
213
|
def self.legacy_keys
|
|
161
|
-
@legacy_keys ||=
|
|
162
|
-
'agent.sockfile_path': :'daemon.sockdir_path',
|
|
163
|
-
'agent.lockfile': :'daemon.pidfile_path'
|
|
164
|
-
)
|
|
214
|
+
@legacy_keys ||= { 'agent.sockfile_path': :'daemon.sockdir_path', 'agent.lockfile': :'daemon.pidfile_path' }
|
|
165
215
|
end
|
|
166
216
|
|
|
167
217
|
def self.validators
|
|
168
|
-
@validators ||=
|
|
169
|
-
'agent.interval': [->(v, _c) { v.is_a?(Integer) && v > 0 }, "must be an integer greater than 0"]
|
|
170
|
-
)
|
|
218
|
+
@validators ||=
|
|
219
|
+
{ 'agent.interval': [->(v, _c) { v.is_a?(Integer) && v > 0 }, "must be an integer greater than 0"] }
|
|
171
220
|
end
|
|
172
221
|
|
|
173
222
|
# @api private
|
|
174
|
-
|
|
175
|
-
|
|
223
|
+
attr_reader :priority_key
|
|
224
|
+
|
|
225
|
+
# @api private
|
|
226
|
+
def initialize(*args)
|
|
227
|
+
attrs = {}
|
|
228
|
+
|
|
229
|
+
attrs = args.pop.dup if args.last.is_a?(Hash)
|
|
230
|
+
|
|
231
|
+
@values = {}
|
|
232
|
+
@priority = {}
|
|
233
|
+
@priority_regexp = nil
|
|
234
|
+
@alert_logger = nil
|
|
235
|
+
@logger = nil
|
|
236
|
+
|
|
237
|
+
p = attrs.delete(:priority)
|
|
238
|
+
|
|
239
|
+
if (@priority_key = args[0])
|
|
240
|
+
@priority_regexp = /^#{Regexp.escape(priority_key)}\.(.+)$/
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
attrs.each { |k, v| self[k] = v }
|
|
244
|
+
|
|
245
|
+
p&.each { |k, v| @priority[self.class.remap_key(k)] = v }
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def self.load(opts = {}, env = ENV)
|
|
249
|
+
attrs = {}
|
|
250
|
+
path = opts.delete(:file)
|
|
251
|
+
priority_key = opts.delete(:priority_key)
|
|
252
|
+
priority_key ||= opts[:env] # if a priority_key is not given, use env if available
|
|
253
|
+
|
|
254
|
+
if path
|
|
255
|
+
error = nil
|
|
256
|
+
begin
|
|
257
|
+
attrs =
|
|
258
|
+
YAML.safe_load(ERB.new(File.read(path)).result, permitted_classes: [], permitted_symbols: [], aliases: true)
|
|
259
|
+
error = "empty file" unless attrs
|
|
260
|
+
error = "invalid format" if attrs && !attrs.is_a?(Hash)
|
|
261
|
+
rescue Exception => e
|
|
262
|
+
error = e.message
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
raise ConfigError, "could not load config file; msg=#{error}" if error
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# The key-value pairs in this `priority` option are inserted into the
|
|
269
|
+
# config's @priority hash *after* anything listed under priority_key;
|
|
270
|
+
# i.e., ENV takes precendence over priority_key
|
|
271
|
+
attrs[:priority] = remap_env(env) if env
|
|
272
|
+
|
|
273
|
+
config = new(priority_key, attrs)
|
|
274
|
+
|
|
275
|
+
opts.each { |k, v| config[k] = v }
|
|
276
|
+
|
|
277
|
+
config
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def self.remap_key(key)
|
|
281
|
+
key = key.to_sym
|
|
282
|
+
legacy_keys[key] || key
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# @api private
|
|
286
|
+
def self.remap_env(env)
|
|
287
|
+
ret = {}
|
|
288
|
+
|
|
289
|
+
return ret unless env
|
|
290
|
+
|
|
291
|
+
# Only set if it exists, we don't want to set to a nil value
|
|
292
|
+
if (proxy_url = Util::Proxy.detect_url(env))
|
|
293
|
+
ret[:proxy_url] = proxy_url
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
env.each do |k, val|
|
|
297
|
+
next unless k =~ /^(?:SK|SKYLIGHT)_(.+)$/
|
|
298
|
+
next unless (key = ENV_TO_KEY[$1])
|
|
299
|
+
|
|
300
|
+
ret[key] =
|
|
301
|
+
case val
|
|
302
|
+
when /^false$/i
|
|
303
|
+
false
|
|
304
|
+
when /^true$/i
|
|
305
|
+
true
|
|
306
|
+
when /^(nil|null)$/i
|
|
307
|
+
nil
|
|
308
|
+
when /^\d+$/
|
|
309
|
+
val.to_i
|
|
310
|
+
when /^\d+\.\d+$/
|
|
311
|
+
val.to_f
|
|
312
|
+
else
|
|
313
|
+
val
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
ret
|
|
176
318
|
end
|
|
177
319
|
|
|
178
320
|
# @api private
|
|
179
321
|
def validate!
|
|
180
|
-
|
|
322
|
+
REQUIRED_KEYS.each { |k, v| raise ConfigError, "#{v} required" unless get(k) }
|
|
323
|
+
|
|
324
|
+
log_file = self[:log_file]
|
|
325
|
+
alert_log_file = self[:alert_log_file]
|
|
326
|
+
native_log_file = self.native_log_file
|
|
327
|
+
|
|
328
|
+
check_logfile_permissions(log_file, "log_file")
|
|
329
|
+
check_logfile_permissions(alert_log_file, "alert_log_file")
|
|
330
|
+
|
|
331
|
+
# TODO: Support rotation interpolation in this check
|
|
332
|
+
check_logfile_permissions(native_log_file, "native_log_file")
|
|
181
333
|
|
|
182
334
|
# TODO: Move this out of the validate! method: https://github.com/tildeio/direwolf-agent/issues/273
|
|
183
335
|
# FIXME: Why not set the sockdir_path and pidfile_path explicitly?
|
|
@@ -191,6 +343,299 @@ module Skylight
|
|
|
191
343
|
true
|
|
192
344
|
end
|
|
193
345
|
|
|
346
|
+
def check_file_permissions(file, key)
|
|
347
|
+
file_root = File.dirname(file)
|
|
348
|
+
|
|
349
|
+
# Try to make the directory, don't blow up if we can't. Our writable? check will fail later.
|
|
350
|
+
begin
|
|
351
|
+
FileUtils.mkdir_p file_root
|
|
352
|
+
rescue StandardError
|
|
353
|
+
nil
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
if File.exist?(file) && !FileTest.writable?(file)
|
|
357
|
+
raise ConfigError, "File `#{file}` is not writable. Please set #{key} in your config to a writable path"
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
unless FileTest.writable?(file_root)
|
|
361
|
+
raise ConfigError,
|
|
362
|
+
"Directory `#{file_root}` is not writable. Please set #{key} in your config to a " \
|
|
363
|
+
"writable path"
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
def check_logfile_permissions(log_file, key)
|
|
368
|
+
return if log_file == "-" # STDOUT
|
|
369
|
+
|
|
370
|
+
log_file = File.expand_path(log_file, root)
|
|
371
|
+
check_file_permissions(log_file, key)
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
def key?(key)
|
|
375
|
+
key = self.class.remap_key(key)
|
|
376
|
+
@priority.key?(key) || @values.key?(key)
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def get(key, default = nil)
|
|
380
|
+
key = self.class.remap_key(key)
|
|
381
|
+
|
|
382
|
+
return @priority[key] if @priority.key?(key)
|
|
383
|
+
return @values[key] if @values.key?(key)
|
|
384
|
+
return self.class.default_values[key] if self.class.default_values.key?(key)
|
|
385
|
+
|
|
386
|
+
if default
|
|
387
|
+
return default
|
|
388
|
+
elsif block_given?
|
|
389
|
+
return yield key
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
nil
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
alias [] get
|
|
396
|
+
|
|
397
|
+
def set(key, val, scope = nil)
|
|
398
|
+
key = [scope, key].join(".") if scope
|
|
399
|
+
|
|
400
|
+
if val.is_a?(Hash)
|
|
401
|
+
val.each { |k, v| set(k, v, key) }
|
|
402
|
+
else
|
|
403
|
+
k = self.class.remap_key(key)
|
|
404
|
+
|
|
405
|
+
if (validator = self.class.validators[k])
|
|
406
|
+
blk, msg = validator
|
|
407
|
+
|
|
408
|
+
unless blk.call(val, self)
|
|
409
|
+
error_msg = "invalid value for #{k} (#{val})"
|
|
410
|
+
error_msg << ", #{msg}" if msg
|
|
411
|
+
raise ConfigError, error_msg
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
@priority[$1.to_sym] = val if @priority_regexp && k =~ @priority_regexp
|
|
416
|
+
|
|
417
|
+
@values[k] = val
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
alias []= set
|
|
422
|
+
|
|
423
|
+
def send_or_get(val)
|
|
424
|
+
respond_to?(val) ? send(val) : get(val)
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
def duration_ms(key, default = nil)
|
|
428
|
+
if (v = self[key]) && v.to_s =~ /^\s*(\d+)(s|sec|ms|micros|nanos)?\s*$/
|
|
429
|
+
v = $1.to_i
|
|
430
|
+
case $2
|
|
431
|
+
when "ms"
|
|
432
|
+
v
|
|
433
|
+
when "micros"
|
|
434
|
+
v / 1_000
|
|
435
|
+
when "nanos"
|
|
436
|
+
v / 1_000_000
|
|
437
|
+
else
|
|
438
|
+
# "s", "sec", nil
|
|
439
|
+
v * 1000
|
|
440
|
+
end
|
|
441
|
+
else
|
|
442
|
+
default
|
|
443
|
+
end
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
def to_native_env
|
|
447
|
+
ret = []
|
|
448
|
+
|
|
449
|
+
self
|
|
450
|
+
.class
|
|
451
|
+
.native_env_keys
|
|
452
|
+
.each do |key|
|
|
453
|
+
value = send_or_get(key)
|
|
454
|
+
unless value.nil?
|
|
455
|
+
env_key = KEY_TO_NATIVE_ENV[key] || ENV_TO_KEY.key(key) || key.upcase
|
|
456
|
+
ret << "SKYLIGHT_#{env_key}" << cast_for_env(value)
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
ret << "SKYLIGHT_AUTHENTICATION" << authentication_with_meta
|
|
461
|
+
ret << "SKYLIGHT_VALIDATE_AUTHENTICATION" << "false"
|
|
462
|
+
|
|
463
|
+
ret
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
#
|
|
467
|
+
#
|
|
468
|
+
# ===== Helpers =====
|
|
469
|
+
#
|
|
470
|
+
#
|
|
471
|
+
|
|
472
|
+
def version
|
|
473
|
+
VERSION
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
# @api private
|
|
477
|
+
def gc
|
|
478
|
+
@gc ||= GC.new(self, get("gc.profiler", VM::GC.new))
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
# @api private
|
|
482
|
+
def ignored_endpoints
|
|
483
|
+
@ignored_endpoints ||=
|
|
484
|
+
begin
|
|
485
|
+
ignored_endpoints = get(:ignored_endpoints)
|
|
486
|
+
|
|
487
|
+
# If, for some odd reason you have a comma in your endpoint name, use the
|
|
488
|
+
# YML config instead.
|
|
489
|
+
ignored_endpoints = ignored_endpoints.split(/\s*,\s*/) if ignored_endpoints.is_a?(String)
|
|
490
|
+
|
|
491
|
+
val = Array(get(:ignored_endpoint))
|
|
492
|
+
val.concat(Array(ignored_endpoints))
|
|
493
|
+
val
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
# @api private
|
|
498
|
+
def source_location_ignored_gems
|
|
499
|
+
@source_location_ignored_gems ||=
|
|
500
|
+
begin
|
|
501
|
+
ignored_gems = get(:source_location_ignored_gems)
|
|
502
|
+
ignored_gems = ignored_gems.split(/\s*,\s*/) if ignored_gems.is_a?(String)
|
|
503
|
+
|
|
504
|
+
Array(ignored_gems) | DEFAULT_IGNORED_SOURCE_LOCATION_GEMS
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
def root
|
|
509
|
+
@root ||= Pathname.new(self[:root] || Dir.pwd).realpath
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
def log_level
|
|
513
|
+
@log_level ||=
|
|
514
|
+
if trace?
|
|
515
|
+
Logger::DEBUG
|
|
516
|
+
else
|
|
517
|
+
case get(:log_level)
|
|
518
|
+
when /^debug$/i
|
|
519
|
+
Logger::DEBUG
|
|
520
|
+
when /^info$/i
|
|
521
|
+
Logger::INFO
|
|
522
|
+
when /^warn$/i
|
|
523
|
+
Logger::WARN
|
|
524
|
+
when /^error$/i
|
|
525
|
+
Logger::ERROR
|
|
526
|
+
when /^fatal$/i
|
|
527
|
+
Logger::FATAL
|
|
528
|
+
else
|
|
529
|
+
Logger::ERROR
|
|
530
|
+
end
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
def native_log_level
|
|
535
|
+
get(:native_log_level).to_s.downcase
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
def logger
|
|
539
|
+
@logger ||= MUTEX.synchronize { load_logger }
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
def native_log_file
|
|
543
|
+
@native_log_file ||=
|
|
544
|
+
get("native_log_file") do
|
|
545
|
+
log_file = self["log_file"]
|
|
546
|
+
return "-" if log_file == "-"
|
|
547
|
+
|
|
548
|
+
parts = log_file.to_s.split(".")
|
|
549
|
+
parts.insert(-2, "native")
|
|
550
|
+
parts.join(".")
|
|
551
|
+
end
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
attr_writer :logger, :alert_logger
|
|
555
|
+
|
|
556
|
+
def alert_logger
|
|
557
|
+
@alert_logger ||=
|
|
558
|
+
MUTEX.synchronize do
|
|
559
|
+
unless (l = @alert_logger)
|
|
560
|
+
out = get(:alert_log_file)
|
|
561
|
+
out = Util::AlertLogger.new(load_logger) if out == "-"
|
|
562
|
+
|
|
563
|
+
l = create_logger(out, level: Logger::DEBUG)
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
l
|
|
567
|
+
end
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
def enable_segments?
|
|
571
|
+
!!get(:enable_segments)
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
def enable_sidekiq?
|
|
575
|
+
!!get(:enable_sidekiq)
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
def sinatra_route_prefixes?
|
|
579
|
+
!!get(:sinatra_route_prefixes)
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
def enable_source_locations?
|
|
583
|
+
!!get(:enable_source_locations)
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
def user_config
|
|
587
|
+
@user_config ||= UserConfig.new(self)
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
def on_heroku?
|
|
591
|
+
File.exist?(get(:'heroku.dyno_info_path'))
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
private
|
|
595
|
+
|
|
596
|
+
def create_logger(out, level: :info)
|
|
597
|
+
if out.is_a?(String)
|
|
598
|
+
out = File.expand_path(out, root)
|
|
599
|
+
|
|
600
|
+
# May be redundant since we also do this in the permissions check
|
|
601
|
+
FileUtils.mkdir_p(File.dirname(out))
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
Logger.new(out, progname: "Skylight", level: level)
|
|
605
|
+
rescue StandardError
|
|
606
|
+
Logger.new($stdout, progname: "Skylight", level: level)
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
def load_logger
|
|
610
|
+
unless (l = @logger)
|
|
611
|
+
out = get(:log_file)
|
|
612
|
+
out = $stdout if out == "-"
|
|
613
|
+
l = create_logger(out, level: log_level)
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
l
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
def cast_for_env(val)
|
|
620
|
+
case val
|
|
621
|
+
when true
|
|
622
|
+
"true"
|
|
623
|
+
when false
|
|
624
|
+
"false"
|
|
625
|
+
when nil
|
|
626
|
+
"nil"
|
|
627
|
+
else
|
|
628
|
+
val.to_s
|
|
629
|
+
end
|
|
630
|
+
end
|
|
631
|
+
|
|
632
|
+
public
|
|
633
|
+
|
|
634
|
+
# @api private
|
|
635
|
+
def api
|
|
636
|
+
@api ||= Api.new(self)
|
|
637
|
+
end
|
|
638
|
+
|
|
194
639
|
def validate_with_server
|
|
195
640
|
res = api.validate_config
|
|
196
641
|
|
|
@@ -199,19 +644,19 @@ module Skylight
|
|
|
199
644
|
return false
|
|
200
645
|
end
|
|
201
646
|
|
|
202
|
-
if res.error_response?
|
|
203
|
-
warn("Unable to reach server for config validation")
|
|
204
|
-
end
|
|
647
|
+
warn("Unable to reach server for config validation") if res.error_response?
|
|
205
648
|
|
|
206
649
|
unless res.config_valid?
|
|
207
650
|
warn("Invalid configuration") unless res.error_response?
|
|
208
|
-
res.validation_errors.each
|
|
209
|
-
warn(" #{k}: #{v}")
|
|
210
|
-
end
|
|
651
|
+
res.validation_errors.each { |k, v| warn(" #{k}: #{v}") }
|
|
211
652
|
|
|
212
653
|
return false if res.forbidden?
|
|
213
654
|
|
|
214
655
|
corrected_config = res.corrected_config
|
|
656
|
+
|
|
657
|
+
# Use defaults if no corrected config is available. This will happen if the request failed.
|
|
658
|
+
corrected_config ||= SERVER_VALIDATE.map { |k| [k, self.class.default_values.fetch(k)] }.to_h
|
|
659
|
+
|
|
215
660
|
config_to_update = corrected_config.reject { |k, v| get(k) == v }
|
|
216
661
|
unless config_to_update.empty?
|
|
217
662
|
info("Updating config values:")
|
|
@@ -220,7 +665,7 @@ module Skylight
|
|
|
220
665
|
|
|
221
666
|
# This is a weird way to handle priorities
|
|
222
667
|
# See https://github.com/tildeio/direwolf-agent/issues/275
|
|
223
|
-
k = "#{
|
|
668
|
+
k = "#{priority_key}.#{k}" if priority_key
|
|
224
669
|
|
|
225
670
|
set(k, v)
|
|
226
671
|
end
|
|
@@ -232,36 +677,33 @@ module Skylight
|
|
|
232
677
|
|
|
233
678
|
def check_sockdir_permissions(sockdir_path)
|
|
234
679
|
# Try to make the directory, don't blow up if we can't. Our writable? check will fail later.
|
|
235
|
-
|
|
680
|
+
begin
|
|
681
|
+
FileUtils.mkdir_p sockdir_path
|
|
682
|
+
rescue StandardError
|
|
683
|
+
nil
|
|
684
|
+
end
|
|
236
685
|
|
|
237
686
|
unless FileTest.writable?(sockdir_path)
|
|
238
|
-
raise
|
|
687
|
+
raise ConfigError,
|
|
688
|
+
"Directory `#{sockdir_path}` is not writable. Please set daemon.sockdir_path in " \
|
|
689
|
+
"your config to a writable path"
|
|
239
690
|
end
|
|
240
691
|
|
|
241
692
|
if check_nfs(sockdir_path)
|
|
242
|
-
raise
|
|
693
|
+
raise ConfigError,
|
|
694
|
+
"Directory `#{sockdir_path}` is an NFS mount and will not allow sockets. Please set " \
|
|
695
|
+
"daemon.sockdir_path in your config to a non-NFS path."
|
|
243
696
|
end
|
|
244
697
|
end
|
|
245
698
|
|
|
246
|
-
def to_native_env
|
|
247
|
-
ret = super
|
|
248
|
-
|
|
249
|
-
ret << "SKYLIGHT_AUTHENTICATION" << authentication_with_meta
|
|
250
|
-
ret << "SKYLIGHT_VALIDATE_AUTHENTICATION" << "false"
|
|
251
|
-
|
|
252
|
-
ret
|
|
253
|
-
end
|
|
254
|
-
|
|
255
699
|
def write(path)
|
|
256
700
|
FileUtils.mkdir_p(File.dirname(path))
|
|
257
701
|
|
|
258
|
-
File.open(path, "w")
|
|
259
|
-
f.puts <<~YAML
|
|
702
|
+
File.open(path, "w") { |f| f.puts <<~YAML }
|
|
260
703
|
---
|
|
261
704
|
# The authentication token for the application.
|
|
262
705
|
authentication: #{self[:authentication]}
|
|
263
706
|
YAML
|
|
264
|
-
end
|
|
265
707
|
end
|
|
266
708
|
|
|
267
709
|
#
|
|
@@ -291,45 +733,38 @@ module Skylight
|
|
|
291
733
|
end
|
|
292
734
|
|
|
293
735
|
def components
|
|
294
|
-
@components ||=
|
|
295
|
-
|
|
296
|
-
get(:env),
|
|
297
|
-
Util::Component
|
|
298
|
-
|
|
299
|
-
worker: Util::Component.new(
|
|
300
|
-
get(:env),
|
|
301
|
-
get(:component) || get(:worker_component),
|
|
302
|
-
force_worker: true
|
|
303
|
-
)
|
|
304
|
-
}
|
|
736
|
+
@components ||=
|
|
737
|
+
{
|
|
738
|
+
web: Util::Component.new(get(:env), Util::Component::DEFAULT_NAME),
|
|
739
|
+
worker: Util::Component.new(get(:env), get(:component) || get(:worker_component), force_worker: true)
|
|
740
|
+
}
|
|
305
741
|
rescue ArgumentError => e
|
|
306
|
-
raise
|
|
742
|
+
raise ConfigError, e.message
|
|
307
743
|
end
|
|
308
744
|
|
|
309
745
|
def component
|
|
310
746
|
components[:web]
|
|
311
747
|
end
|
|
312
748
|
|
|
749
|
+
def to_json(*)
|
|
750
|
+
JSON.generate(as_json)
|
|
751
|
+
end
|
|
752
|
+
|
|
313
753
|
def as_json(*)
|
|
314
|
-
{
|
|
315
|
-
config: {
|
|
316
|
-
priority: @priority.merge(component.as_json),
|
|
317
|
-
values: @values
|
|
318
|
-
}
|
|
319
|
-
}
|
|
754
|
+
{ config: { priority: @priority.merge(component.as_json), values: @values } }
|
|
320
755
|
end
|
|
321
756
|
|
|
322
757
|
private
|
|
323
758
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
759
|
+
def check_nfs(path)
|
|
760
|
+
# Should work on most *nix, though not on OS X
|
|
761
|
+
`stat -f -L -c %T #{path} 2>&1`.strip == "nfs"
|
|
762
|
+
end
|
|
328
763
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
764
|
+
def reporting_env?
|
|
765
|
+
# true if env was explicitly set,
|
|
766
|
+
# or if we are auto-detecting via the opt-in SKYLIGHT_REPORT_RAILS_ENV=true
|
|
767
|
+
!!(get(:report_rails_env) || get(:env))
|
|
768
|
+
end
|
|
334
769
|
end
|
|
335
770
|
end
|