skylight-core 2.0.0.beta1
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/lib/skylight/core/config.rb +454 -0
- data/lib/skylight/core/errors.rb +6 -0
- data/lib/skylight/core/fanout.rb +44 -0
- data/lib/skylight/core/formatters/http.rb +23 -0
- data/lib/skylight/core/gc.rb +107 -0
- data/lib/skylight/core/instrumentable.rb +144 -0
- data/lib/skylight/core/instrumenter.rb +249 -0
- data/lib/skylight/core/middleware.rb +101 -0
- data/lib/skylight/core/normalizers/action_controller/process_action.rb +50 -0
- data/lib/skylight/core/normalizers/action_controller/send_file.rb +50 -0
- data/lib/skylight/core/normalizers/action_view/render_collection.rb +22 -0
- data/lib/skylight/core/normalizers/action_view/render_partial.rb +21 -0
- data/lib/skylight/core/normalizers/action_view/render_template.rb +21 -0
- data/lib/skylight/core/normalizers/active_job/enqueue_at.rb +21 -0
- data/lib/skylight/core/normalizers/active_model_serializers/render.rb +26 -0
- data/lib/skylight/core/normalizers/active_record/instantiation.rb +17 -0
- data/lib/skylight/core/normalizers/active_record/sql.rb +33 -0
- data/lib/skylight/core/normalizers/active_support/cache.rb +20 -0
- data/lib/skylight/core/normalizers/active_support/cache_clear.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_decrement.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_delete.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_exist.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_fetch_hit.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_generate.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_increment.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_read.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_read_multi.rb +16 -0
- data/lib/skylight/core/normalizers/active_support/cache_write.rb +16 -0
- data/lib/skylight/core/normalizers/coach/handler_finish.rb +36 -0
- data/lib/skylight/core/normalizers/coach/middleware_finish.rb +23 -0
- data/lib/skylight/core/normalizers/couch_potato/query.rb +20 -0
- data/lib/skylight/core/normalizers/data_mapper/sql.rb +12 -0
- data/lib/skylight/core/normalizers/default.rb +27 -0
- data/lib/skylight/core/normalizers/elasticsearch/request.rb +20 -0
- data/lib/skylight/core/normalizers/faraday/request.rb +37 -0
- data/lib/skylight/core/normalizers/grape/endpoint.rb +30 -0
- data/lib/skylight/core/normalizers/grape/endpoint_render.rb +26 -0
- data/lib/skylight/core/normalizers/grape/endpoint_run.rb +33 -0
- data/lib/skylight/core/normalizers/grape/endpoint_run_filters.rb +23 -0
- data/lib/skylight/core/normalizers/moped/query.rb +100 -0
- data/lib/skylight/core/normalizers/sequel/sql.rb +12 -0
- data/lib/skylight/core/normalizers/sql.rb +49 -0
- data/lib/skylight/core/normalizers.rb +170 -0
- data/lib/skylight/core/probes/action_controller.rb +31 -0
- data/lib/skylight/core/probes/action_view.rb +37 -0
- data/lib/skylight/core/probes/active_model_serializers.rb +55 -0
- data/lib/skylight/core/probes/elasticsearch.rb +37 -0
- data/lib/skylight/core/probes/excon/middleware.rb +72 -0
- data/lib/skylight/core/probes/excon.rb +26 -0
- data/lib/skylight/core/probes/faraday.rb +22 -0
- data/lib/skylight/core/probes/grape.rb +80 -0
- data/lib/skylight/core/probes/httpclient.rb +46 -0
- data/lib/skylight/core/probes/middleware.rb +58 -0
- data/lib/skylight/core/probes/mongo.rb +171 -0
- data/lib/skylight/core/probes/mongoid.rb +21 -0
- data/lib/skylight/core/probes/moped.rb +39 -0
- data/lib/skylight/core/probes/net_http.rb +64 -0
- data/lib/skylight/core/probes/redis.rb +71 -0
- data/lib/skylight/core/probes/sequel.rb +33 -0
- data/lib/skylight/core/probes/sinatra.rb +69 -0
- data/lib/skylight/core/probes/tilt.rb +27 -0
- data/lib/skylight/core/probes.rb +129 -0
- data/lib/skylight/core/railtie.rb +166 -0
- data/lib/skylight/core/subscriber.rb +124 -0
- data/lib/skylight/core/test.rb +98 -0
- data/lib/skylight/core/trace.rb +190 -0
- data/lib/skylight/core/user_config.rb +61 -0
- data/lib/skylight/core/util/allocation_free.rb +26 -0
- data/lib/skylight/core/util/clock.rb +56 -0
- data/lib/skylight/core/util/deploy.rb +132 -0
- data/lib/skylight/core/util/gzip.rb +21 -0
- data/lib/skylight/core/util/inflector.rb +112 -0
- data/lib/skylight/core/util/logging.rb +127 -0
- data/lib/skylight/core/util/platform.rb +77 -0
- data/lib/skylight/core/util/proxy.rb +13 -0
- data/lib/skylight/core/util.rb +14 -0
- data/lib/skylight/core/vendor/active_support/notifications.rb +207 -0
- data/lib/skylight/core/vendor/active_support/per_thread_registry.rb +52 -0
- data/lib/skylight/core/vendor/thread_safe/non_concurrent_cache_backend.rb +133 -0
- data/lib/skylight/core/vendor/thread_safe/synchronized_cache_backend.rb +76 -0
- data/lib/skylight/core/vendor/thread_safe.rb +126 -0
- data/lib/skylight/core/version.rb +6 -0
- data/lib/skylight/core/vm/gc.rb +70 -0
- data/lib/skylight/core.rb +99 -0
- metadata +254 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 5f2101f565718179a58601c833bd3005ce789b2159c689dcf4a68f02ee4ead8e
|
|
4
|
+
data.tar.gz: 34f6391c7691bdb47b33bef9dc0fddc3808d98d82eb809adaebe3dfb4d4a6aa6
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: f867502b872f1604375b24a7a4591c4d733f38327b1d985a7bd8a5d2b64cff5a7fa59482357d88fc7fd0e1314c7200f054f448df07e398c1c14aa00e0bcb148c
|
|
7
|
+
data.tar.gz: b021ff2ed79a9f52cd9eaab91a3377547318195e6c7a2a11fed443565527245029b85970720fd9ef573064fe3443743339fc10ed4d8eb4cb6b2056fb68a9879b
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
require 'thread'
|
|
4
|
+
require 'erb'
|
|
5
|
+
require 'json'
|
|
6
|
+
require 'skylight/core/util/logging'
|
|
7
|
+
require 'skylight/core/util/proxy'
|
|
8
|
+
require 'skylight/core/errors'
|
|
9
|
+
|
|
10
|
+
module Skylight::Core
|
|
11
|
+
class Config
|
|
12
|
+
include Util::Logging
|
|
13
|
+
|
|
14
|
+
# @api private
|
|
15
|
+
MUTEX = Mutex.new
|
|
16
|
+
|
|
17
|
+
def self.env_matcher; /^(?:SK|SKYLIGHT)_(.+)$/ end
|
|
18
|
+
def self.native_env_prefix; "SKYLIGHT_" end
|
|
19
|
+
|
|
20
|
+
# Map environment variable keys with Skylight configuration keys
|
|
21
|
+
def self.env_to_key
|
|
22
|
+
{
|
|
23
|
+
# == Logging ==
|
|
24
|
+
'LOG_FILE' => :log_file,
|
|
25
|
+
'LOG_LEVEL' => :log_level,
|
|
26
|
+
'ALERT_LOG_FILE' => :alert_log_file,
|
|
27
|
+
'LOG_SQL_PARSE_ERRORS' => :log_sql_parse_errors,
|
|
28
|
+
|
|
29
|
+
# == Proxy ==
|
|
30
|
+
'PROXY_URL' => :proxy_url,
|
|
31
|
+
|
|
32
|
+
# == Instrumenter ==
|
|
33
|
+
"ENABLE_SEGMENTS" => :enable_segments,
|
|
34
|
+
|
|
35
|
+
# == User config settings ==
|
|
36
|
+
"USER_CONFIG_PATH" => :'user_config_path',
|
|
37
|
+
|
|
38
|
+
# == Heroku settings ==
|
|
39
|
+
#
|
|
40
|
+
"HEROKU_DYNO_INFO_PATH" => :'heroku.dyno_info_path'
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Default values for Skylight configuration keys
|
|
45
|
+
def self.default_values
|
|
46
|
+
{
|
|
47
|
+
:log_file => '-'.freeze,
|
|
48
|
+
:log_level => 'INFO'.freeze,
|
|
49
|
+
:alert_log_file => '-'.freeze,
|
|
50
|
+
:log_sql_parse_errors => false,
|
|
51
|
+
:enable_segments => true,
|
|
52
|
+
:'heroku.dyno_info_path' => '/etc/heroku/dyno'
|
|
53
|
+
}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def self.required_keys
|
|
57
|
+
# Nothing is required in this base class.
|
|
58
|
+
{}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def self.server_validated_keys
|
|
62
|
+
# Nothing is validated for now, but this is a list of symbols
|
|
63
|
+
# for the key we want to validate.
|
|
64
|
+
[]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def self.native_env_keys
|
|
68
|
+
[
|
|
69
|
+
:version,
|
|
70
|
+
:root,
|
|
71
|
+
:proxy_url
|
|
72
|
+
]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Maps legacy config keys to new config keys
|
|
76
|
+
def self.legacy_keys
|
|
77
|
+
# No legacy keys for now
|
|
78
|
+
{}
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self.validators
|
|
82
|
+
# None for now
|
|
83
|
+
{}
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @api private
|
|
87
|
+
attr_reader :environment
|
|
88
|
+
|
|
89
|
+
# @api private
|
|
90
|
+
def initialize(*args)
|
|
91
|
+
attrs = {}
|
|
92
|
+
|
|
93
|
+
if Hash === args.last
|
|
94
|
+
attrs = args.pop.dup
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
@values = {}
|
|
98
|
+
@priority = {}
|
|
99
|
+
@regexp = nil
|
|
100
|
+
|
|
101
|
+
p = attrs.delete(:priority)
|
|
102
|
+
|
|
103
|
+
if @environment = args[0]
|
|
104
|
+
@regexp = /^#{Regexp.escape(@environment)}\.(.+)$/
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
attrs.each do |k, v|
|
|
108
|
+
self[k] = v
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
if p
|
|
112
|
+
p.each do |k, v|
|
|
113
|
+
@priority[self.class.remap_key(k)] = v
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def self.load(opts = {}, env = ENV)
|
|
119
|
+
attrs = {}
|
|
120
|
+
version = nil
|
|
121
|
+
|
|
122
|
+
path = opts.delete(:file)
|
|
123
|
+
environment = opts.delete(:environment)
|
|
124
|
+
|
|
125
|
+
if path
|
|
126
|
+
error = nil
|
|
127
|
+
begin
|
|
128
|
+
attrs = YAML.load(ERB.new(File.read(path)).result)
|
|
129
|
+
error = "empty file" unless attrs
|
|
130
|
+
error = "invalid format" if attrs && !attrs.is_a?(Hash)
|
|
131
|
+
rescue Exception => e
|
|
132
|
+
error = e.message
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
raise ConfigError, "could not load config file; msg=#{error}" if error
|
|
136
|
+
|
|
137
|
+
version = File.mtime(path).to_i
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
if env
|
|
141
|
+
attrs[:priority] = remap_env(env)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
config = new(environment, attrs)
|
|
145
|
+
|
|
146
|
+
opts.each do |k, v|
|
|
147
|
+
config[k] = v
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
config
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def self.remap_key(key)
|
|
154
|
+
key = key.to_sym
|
|
155
|
+
legacy_keys[key] || key
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# @api private
|
|
159
|
+
def self.remap_env(env)
|
|
160
|
+
ret = {}
|
|
161
|
+
|
|
162
|
+
return ret unless env
|
|
163
|
+
|
|
164
|
+
# Only set if it exists, we don't want to set to a nil value
|
|
165
|
+
if proxy_url = Util::Proxy.detect_url(env)
|
|
166
|
+
ret[:proxy_url] = proxy_url
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
env.each do |k, val|
|
|
170
|
+
next unless k =~ env_matcher
|
|
171
|
+
|
|
172
|
+
if key = env_to_key[$1]
|
|
173
|
+
ret[key] =
|
|
174
|
+
case val
|
|
175
|
+
when /^false$/i then false
|
|
176
|
+
when /^true$/i then true
|
|
177
|
+
when /^(nil|null)$/i then nil
|
|
178
|
+
when /^\d+$/ then val.to_i
|
|
179
|
+
when /^\d+\.\d+$/ then val.to_f
|
|
180
|
+
else val
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
ret
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# @api private
|
|
189
|
+
def validate!
|
|
190
|
+
self.class.required_keys.each do |k, v|
|
|
191
|
+
unless get(k)
|
|
192
|
+
raise ConfigError, "#{v} required"
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
log_file = self[:log_file]
|
|
197
|
+
alert_log_file = self[:alert_log_file]
|
|
198
|
+
|
|
199
|
+
check_logfile_permissions(log_file, "log_file")
|
|
200
|
+
check_logfile_permissions(alert_log_file, "alert_log_file")
|
|
201
|
+
|
|
202
|
+
true
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def validate_with_server
|
|
206
|
+
true
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def check_file_permissions(file, key)
|
|
210
|
+
file_root = File.dirname(file)
|
|
211
|
+
|
|
212
|
+
# Try to make the directory, don't blow up if we can't. Our writable? check will fail later.
|
|
213
|
+
FileUtils.mkdir_p file_root rescue nil
|
|
214
|
+
|
|
215
|
+
if File.exist?(file) && !FileTest.writable?(file)
|
|
216
|
+
raise ConfigError, "File `#{file}` is not writable. Please set #{key} in your config to a writable path"
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
unless FileTest.writable?(file_root)
|
|
220
|
+
raise ConfigError, "Directory `#{file_root}` is not writable. Please set #{key} in your config to a writable path"
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def check_logfile_permissions(log_file, key)
|
|
225
|
+
return if log_file == '-' # STDOUT
|
|
226
|
+
log_file = File.expand_path(log_file, root)
|
|
227
|
+
check_file_permissions(log_file, key)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def key?(key)
|
|
231
|
+
key = self.class.remap_key(key)
|
|
232
|
+
@priority.key?(key) || @values.key?(key)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def get(key, default = nil, &blk)
|
|
236
|
+
key = self.class.remap_key(key)
|
|
237
|
+
|
|
238
|
+
return @priority[key] if @priority.key?(key)
|
|
239
|
+
return @values[key] if @values.key?(key)
|
|
240
|
+
return self.class.default_values[key] if self.class.default_values.key?(key)
|
|
241
|
+
|
|
242
|
+
if default
|
|
243
|
+
return default
|
|
244
|
+
elsif blk
|
|
245
|
+
return blk.call(key)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
nil
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
alias [] get
|
|
252
|
+
|
|
253
|
+
def set(key, val, scope = nil)
|
|
254
|
+
if scope
|
|
255
|
+
key = [scope, key].join('.')
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
if Hash === val
|
|
259
|
+
val.each do |k, v|
|
|
260
|
+
set(k, v, key)
|
|
261
|
+
end
|
|
262
|
+
else
|
|
263
|
+
k = self.class.remap_key(key)
|
|
264
|
+
|
|
265
|
+
if validator = self.class.validators[k]
|
|
266
|
+
blk, msg = validator
|
|
267
|
+
|
|
268
|
+
unless blk.call(val, self)
|
|
269
|
+
error_msg = "invalid value for #{k} (#{val})"
|
|
270
|
+
error_msg << ", #{msg}" if msg
|
|
271
|
+
raise ConfigError, error_msg
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
if @regexp && k =~ @regexp
|
|
276
|
+
@priority[$1.to_sym] = val
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
@values[k] = val
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
alias []= set
|
|
284
|
+
|
|
285
|
+
def send_or_get(v)
|
|
286
|
+
respond_to?(v) ? send(v) : get(v)
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def duration_ms(key, default = nil)
|
|
290
|
+
if (v = self[key]) && v.to_s =~ /^\s*(\d+)(s|sec|ms|micros|nanos)?\s*$/
|
|
291
|
+
v = $1.to_i
|
|
292
|
+
case $2
|
|
293
|
+
when "ms"
|
|
294
|
+
v
|
|
295
|
+
when "micros"
|
|
296
|
+
v / 1_000
|
|
297
|
+
when "nanos"
|
|
298
|
+
v / 1_000_000
|
|
299
|
+
else # "s", "sec", nil
|
|
300
|
+
v * 1000
|
|
301
|
+
end
|
|
302
|
+
else
|
|
303
|
+
default
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def to_json
|
|
308
|
+
JSON.generate(
|
|
309
|
+
config: {
|
|
310
|
+
priority: @priority,
|
|
311
|
+
values: @values
|
|
312
|
+
}
|
|
313
|
+
)
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def to_native_env
|
|
317
|
+
ret = []
|
|
318
|
+
|
|
319
|
+
self.class.native_env_keys.each do |key|
|
|
320
|
+
value = send_or_get(key)
|
|
321
|
+
unless value.nil?
|
|
322
|
+
env_key = self.class.env_to_key.key(key) || key.upcase
|
|
323
|
+
ret << "#{self.class.native_env_prefix}#{env_key}" << cast_for_env(value)
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
ret
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def write(path)
|
|
331
|
+
raise "not implemented"
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
#
|
|
335
|
+
#
|
|
336
|
+
# ===== Helpers =====
|
|
337
|
+
#
|
|
338
|
+
#
|
|
339
|
+
|
|
340
|
+
def version
|
|
341
|
+
VERSION
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# @api private
|
|
345
|
+
def gc
|
|
346
|
+
@gc ||= GC.new(self, get('gc.profiler', VM::GC.new))
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# @api private
|
|
350
|
+
def ignored_endpoints
|
|
351
|
+
@ignored_endpoints ||=
|
|
352
|
+
begin
|
|
353
|
+
ignored_endpoints = get(:ignored_endpoints)
|
|
354
|
+
|
|
355
|
+
# If, for some odd reason you have a comma in your endpoint name, use the
|
|
356
|
+
# YML config instead.
|
|
357
|
+
if ignored_endpoints.is_a?(String)
|
|
358
|
+
ignored_endpoints = ignored_endpoints.split(/\s*,\s*/)
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
val = Array(get(:ignored_endpoint))
|
|
362
|
+
val.concat(Array(ignored_endpoints))
|
|
363
|
+
val
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
def root
|
|
368
|
+
self[:root] || Dir.pwd
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def logger
|
|
372
|
+
@logger ||=
|
|
373
|
+
MUTEX.synchronize do
|
|
374
|
+
load_logger
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
def logger=(logger)
|
|
379
|
+
@logger = logger
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def alert_logger
|
|
383
|
+
@alert_logger ||= MUTEX.synchronize do
|
|
384
|
+
unless l = @alert_logger
|
|
385
|
+
out = get(:alert_log_file)
|
|
386
|
+
out = Util::AlertLogger.new(load_logger) if out == '-'
|
|
387
|
+
|
|
388
|
+
l = create_logger(out)
|
|
389
|
+
l.level = Logger::DEBUG
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
l
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
def alert_logger=(logger)
|
|
397
|
+
@alert_logger = logger
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
def enable_segments?
|
|
401
|
+
!!get(:enable_segments)
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
def user_config
|
|
405
|
+
@user_config ||= UserConfig.new(self)
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
def on_heroku?
|
|
409
|
+
File.exist?(get(:'heroku.dyno_info_path'))
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
private
|
|
413
|
+
|
|
414
|
+
def create_logger(out)
|
|
415
|
+
if out.is_a?(String)
|
|
416
|
+
out = File.expand_path(out, root)
|
|
417
|
+
# May be redundant since we also do this in the permissions check
|
|
418
|
+
FileUtils.mkdir_p(File.dirname(out))
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
Logger.new(out)
|
|
422
|
+
rescue
|
|
423
|
+
Logger.new(STDOUT)
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
def load_logger
|
|
427
|
+
unless l = @logger
|
|
428
|
+
out = get(:log_file)
|
|
429
|
+
out = STDOUT if out == '-'
|
|
430
|
+
|
|
431
|
+
l = create_logger(out)
|
|
432
|
+
l.level =
|
|
433
|
+
case get(:log_level)
|
|
434
|
+
when /^debug$/i then Logger::DEBUG
|
|
435
|
+
when /^info$/i then Logger::INFO
|
|
436
|
+
when /^warn$/i then Logger::WARN
|
|
437
|
+
when /^error$/i then Logger::ERROR
|
|
438
|
+
end
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
l
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
def cast_for_env(v)
|
|
445
|
+
case v
|
|
446
|
+
when true then 'true'
|
|
447
|
+
when false then 'false'
|
|
448
|
+
when nil then 'nil'
|
|
449
|
+
else v.to_s
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
end
|
|
454
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Core
|
|
3
|
+
module Fanout
|
|
4
|
+
|
|
5
|
+
def self.registered
|
|
6
|
+
@registered ||= []
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.register(obj)
|
|
10
|
+
registered.push(obj)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.unregister(obj)
|
|
14
|
+
registered.delete(obj)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.trace(*args)
|
|
18
|
+
registered.map{|r| r.trace(*args) }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.instrument(*args)
|
|
22
|
+
if block_given?
|
|
23
|
+
spans = instrument(*args)
|
|
24
|
+
begin
|
|
25
|
+
yield spans
|
|
26
|
+
ensure
|
|
27
|
+
done(spans)
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
registered.map do |r|
|
|
31
|
+
[r, r.instrument(*args)]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.done(spans, meta=nil)
|
|
37
|
+
spans.reverse.each do |(target, span)|
|
|
38
|
+
target.done(span, meta)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Core
|
|
3
|
+
module Formatters
|
|
4
|
+
module HTTP
|
|
5
|
+
|
|
6
|
+
# Build instrumentation options for HTTP queries
|
|
7
|
+
#
|
|
8
|
+
# @param [String] method HTTP method, e.g. get, post
|
|
9
|
+
# @param [String] scheme HTTP scheme, e.g. http, https
|
|
10
|
+
# @param [String] host Request host, e.g. example.com
|
|
11
|
+
# @param [String, Integer] port Request port
|
|
12
|
+
# @param [String] path Request path
|
|
13
|
+
# @param [String] query Request query string
|
|
14
|
+
# @return [Hash] a hash containing `:category`, `:title`, and `:annotations`
|
|
15
|
+
def self.build_opts(method, scheme, host, port, path, query)
|
|
16
|
+
{ category: "api.http.#{method.downcase}",
|
|
17
|
+
title: "#{method.upcase} #{host}",
|
|
18
|
+
meta: { host: host } }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
require 'thread'
|
|
2
|
+
|
|
3
|
+
module Skylight::Core
|
|
4
|
+
# @api private
|
|
5
|
+
class GC
|
|
6
|
+
METHODS = [ :enable, :total_time ]
|
|
7
|
+
TH_KEY = :SK_GC_CURR_WINDOW
|
|
8
|
+
MAX_COUNT = 1000
|
|
9
|
+
MAX_TIME = 30_000_000
|
|
10
|
+
|
|
11
|
+
include Util::Logging
|
|
12
|
+
|
|
13
|
+
attr_reader :config
|
|
14
|
+
|
|
15
|
+
def initialize(config, profiler)
|
|
16
|
+
@listeners = []
|
|
17
|
+
@config = config
|
|
18
|
+
@lock = Mutex.new
|
|
19
|
+
@time = 0
|
|
20
|
+
|
|
21
|
+
if METHODS.all? { |m| profiler.respond_to?(m) }
|
|
22
|
+
@profiler = profiler
|
|
23
|
+
@time = @profiler.total_time
|
|
24
|
+
else
|
|
25
|
+
debug "disabling GC profiling"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def enable
|
|
30
|
+
@profiler.enable if @profiler
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def track
|
|
34
|
+
unless @profiler
|
|
35
|
+
win = Window.new(nil)
|
|
36
|
+
else
|
|
37
|
+
win = Window.new(self)
|
|
38
|
+
|
|
39
|
+
@lock.synchronize do
|
|
40
|
+
__update
|
|
41
|
+
@listeners << win
|
|
42
|
+
|
|
43
|
+
# Cleanup any listeners that might have leaked
|
|
44
|
+
until @listeners[0].time < MAX_TIME
|
|
45
|
+
@listeners.shift
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
if @listeners.length > MAX_COUNT
|
|
49
|
+
@listeners.shift
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
win
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def release(win)
|
|
58
|
+
@lock.synchronize do
|
|
59
|
+
@listeners.delete(win)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def update
|
|
64
|
+
@lock.synchronize do
|
|
65
|
+
__update
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
nil
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def __update
|
|
74
|
+
time = @profiler.total_time
|
|
75
|
+
diff = time - @time
|
|
76
|
+
@time = time
|
|
77
|
+
|
|
78
|
+
if diff > 0
|
|
79
|
+
@listeners.each do |l|
|
|
80
|
+
l.add(diff)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class Window
|
|
86
|
+
attr_reader :time
|
|
87
|
+
|
|
88
|
+
def initialize(global)
|
|
89
|
+
@global = global
|
|
90
|
+
@time = 0
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def update
|
|
94
|
+
@global.update if @global
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def add(time)
|
|
98
|
+
@time += time
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def release
|
|
102
|
+
@global.release(self) if @global
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
end
|
|
107
|
+
end
|