truex-skylight 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +277 -0
  3. data/CLA.md +9 -0
  4. data/CONTRIBUTING.md +1 -0
  5. data/LICENSE.md +79 -0
  6. data/README.md +4 -0
  7. data/bin/skylight +3 -0
  8. data/ext/extconf.rb +186 -0
  9. data/ext/libskylight.yml +6 -0
  10. data/ext/skylight_memprof.c +115 -0
  11. data/ext/skylight_native.c +416 -0
  12. data/ext/skylight_native.h +20 -0
  13. data/lib/skylight.rb +2 -0
  14. data/lib/skylight/api.rb +79 -0
  15. data/lib/skylight/cli.rb +146 -0
  16. data/lib/skylight/compat.rb +47 -0
  17. data/lib/skylight/config.rb +498 -0
  18. data/lib/skylight/core.rb +122 -0
  19. data/lib/skylight/data/cacert.pem +3894 -0
  20. data/lib/skylight/formatters/http.rb +17 -0
  21. data/lib/skylight/gc.rb +107 -0
  22. data/lib/skylight/helpers.rb +137 -0
  23. data/lib/skylight/instrumenter.rb +290 -0
  24. data/lib/skylight/middleware.rb +75 -0
  25. data/lib/skylight/native.rb +69 -0
  26. data/lib/skylight/normalizers.rb +133 -0
  27. data/lib/skylight/normalizers/action_controller/process_action.rb +35 -0
  28. data/lib/skylight/normalizers/action_controller/send_file.rb +76 -0
  29. data/lib/skylight/normalizers/action_view/render_collection.rb +18 -0
  30. data/lib/skylight/normalizers/action_view/render_partial.rb +18 -0
  31. data/lib/skylight/normalizers/action_view/render_template.rb +18 -0
  32. data/lib/skylight/normalizers/active_record/sql.rb +79 -0
  33. data/lib/skylight/normalizers/active_support/cache.rb +50 -0
  34. data/lib/skylight/normalizers/active_support/cache_clear.rb +16 -0
  35. data/lib/skylight/normalizers/active_support/cache_decrement.rb +16 -0
  36. data/lib/skylight/normalizers/active_support/cache_delete.rb +16 -0
  37. data/lib/skylight/normalizers/active_support/cache_exist.rb +16 -0
  38. data/lib/skylight/normalizers/active_support/cache_fetch_hit.rb +16 -0
  39. data/lib/skylight/normalizers/active_support/cache_generate.rb +16 -0
  40. data/lib/skylight/normalizers/active_support/cache_increment.rb +16 -0
  41. data/lib/skylight/normalizers/active_support/cache_read.rb +16 -0
  42. data/lib/skylight/normalizers/active_support/cache_read_multi.rb +16 -0
  43. data/lib/skylight/normalizers/active_support/cache_write.rb +16 -0
  44. data/lib/skylight/normalizers/default.rb +21 -0
  45. data/lib/skylight/normalizers/moped/query.rb +141 -0
  46. data/lib/skylight/probes.rb +91 -0
  47. data/lib/skylight/probes/excon.rb +25 -0
  48. data/lib/skylight/probes/excon/middleware.rb +65 -0
  49. data/lib/skylight/probes/net_http.rb +44 -0
  50. data/lib/skylight/probes/redis.rb +30 -0
  51. data/lib/skylight/probes/sequel.rb +30 -0
  52. data/lib/skylight/probes/sinatra.rb +74 -0
  53. data/lib/skylight/probes/tilt.rb +27 -0
  54. data/lib/skylight/railtie.rb +122 -0
  55. data/lib/skylight/sinatra.rb +4 -0
  56. data/lib/skylight/subscriber.rb +92 -0
  57. data/lib/skylight/trace.rb +191 -0
  58. data/lib/skylight/util.rb +16 -0
  59. data/lib/skylight/util/allocation_free.rb +17 -0
  60. data/lib/skylight/util/clock.rb +53 -0
  61. data/lib/skylight/util/gzip.rb +15 -0
  62. data/lib/skylight/util/hostname.rb +17 -0
  63. data/lib/skylight/util/http.rb +218 -0
  64. data/lib/skylight/util/inflector.rb +110 -0
  65. data/lib/skylight/util/logging.rb +87 -0
  66. data/lib/skylight/util/multi_io.rb +21 -0
  67. data/lib/skylight/util/native_ext_fetcher.rb +205 -0
  68. data/lib/skylight/util/platform.rb +67 -0
  69. data/lib/skylight/util/ssl.rb +50 -0
  70. data/lib/skylight/vendor/active_support/notifications.rb +207 -0
  71. data/lib/skylight/vendor/active_support/notifications/fanout.rb +159 -0
  72. data/lib/skylight/vendor/active_support/notifications/instrumenter.rb +72 -0
  73. data/lib/skylight/vendor/active_support/per_thread_registry.rb +52 -0
  74. data/lib/skylight/vendor/cli/highline.rb +1034 -0
  75. data/lib/skylight/vendor/cli/highline/color_scheme.rb +134 -0
  76. data/lib/skylight/vendor/cli/highline/compatibility.rb +16 -0
  77. data/lib/skylight/vendor/cli/highline/import.rb +41 -0
  78. data/lib/skylight/vendor/cli/highline/menu.rb +381 -0
  79. data/lib/skylight/vendor/cli/highline/question.rb +481 -0
  80. data/lib/skylight/vendor/cli/highline/simulate.rb +48 -0
  81. data/lib/skylight/vendor/cli/highline/string_extensions.rb +111 -0
  82. data/lib/skylight/vendor/cli/highline/style.rb +181 -0
  83. data/lib/skylight/vendor/cli/highline/system_extensions.rb +242 -0
  84. data/lib/skylight/vendor/cli/thor.rb +473 -0
  85. data/lib/skylight/vendor/cli/thor/actions.rb +318 -0
  86. data/lib/skylight/vendor/cli/thor/actions/create_file.rb +105 -0
  87. data/lib/skylight/vendor/cli/thor/actions/create_link.rb +60 -0
  88. data/lib/skylight/vendor/cli/thor/actions/directory.rb +119 -0
  89. data/lib/skylight/vendor/cli/thor/actions/empty_directory.rb +137 -0
  90. data/lib/skylight/vendor/cli/thor/actions/file_manipulation.rb +314 -0
  91. data/lib/skylight/vendor/cli/thor/actions/inject_into_file.rb +109 -0
  92. data/lib/skylight/vendor/cli/thor/base.rb +652 -0
  93. data/lib/skylight/vendor/cli/thor/command.rb +136 -0
  94. data/lib/skylight/vendor/cli/thor/core_ext/hash_with_indifferent_access.rb +80 -0
  95. data/lib/skylight/vendor/cli/thor/core_ext/io_binary_read.rb +12 -0
  96. data/lib/skylight/vendor/cli/thor/core_ext/ordered_hash.rb +100 -0
  97. data/lib/skylight/vendor/cli/thor/error.rb +28 -0
  98. data/lib/skylight/vendor/cli/thor/group.rb +282 -0
  99. data/lib/skylight/vendor/cli/thor/invocation.rb +172 -0
  100. data/lib/skylight/vendor/cli/thor/parser.rb +4 -0
  101. data/lib/skylight/vendor/cli/thor/parser/argument.rb +74 -0
  102. data/lib/skylight/vendor/cli/thor/parser/arguments.rb +171 -0
  103. data/lib/skylight/vendor/cli/thor/parser/option.rb +121 -0
  104. data/lib/skylight/vendor/cli/thor/parser/options.rb +218 -0
  105. data/lib/skylight/vendor/cli/thor/rake_compat.rb +72 -0
  106. data/lib/skylight/vendor/cli/thor/runner.rb +322 -0
  107. data/lib/skylight/vendor/cli/thor/shell.rb +88 -0
  108. data/lib/skylight/vendor/cli/thor/shell/basic.rb +393 -0
  109. data/lib/skylight/vendor/cli/thor/shell/color.rb +148 -0
  110. data/lib/skylight/vendor/cli/thor/shell/html.rb +127 -0
  111. data/lib/skylight/vendor/cli/thor/util.rb +270 -0
  112. data/lib/skylight/vendor/cli/thor/version.rb +3 -0
  113. data/lib/skylight/vendor/thread_safe.rb +126 -0
  114. data/lib/skylight/vendor/thread_safe/non_concurrent_cache_backend.rb +133 -0
  115. data/lib/skylight/vendor/thread_safe/synchronized_cache_backend.rb +76 -0
  116. data/lib/skylight/version.rb +4 -0
  117. data/lib/skylight/vm/gc.rb +70 -0
  118. data/lib/sql_lexer.rb +6 -0
  119. data/lib/sql_lexer/lexer.rb +579 -0
  120. data/lib/sql_lexer/string_scanner.rb +11 -0
  121. data/lib/sql_lexer/version.rb +3 -0
  122. metadata +179 -0
@@ -0,0 +1,91 @@
1
+ module Skylight
2
+ # @api private
3
+ module Probes
4
+ class ProbeRegistration
5
+ attr_reader :klass_name, :require_paths, :probe
6
+
7
+ def initialize(klass_name, require_paths, probe)
8
+ @klass_name = klass_name
9
+ @require_paths = Array(require_paths)
10
+ @probe = probe
11
+ end
12
+
13
+ def install
14
+ probe.install
15
+ end
16
+ end
17
+
18
+ def self.require_hooks
19
+ @require_hooks ||= {}
20
+ end
21
+
22
+ def self.installed
23
+ @installed ||= {}
24
+ end
25
+
26
+ def self.is_available?(klass_name)
27
+ !!Skylight::Util::Inflector.safe_constantize(klass_name)
28
+ end
29
+
30
+ def self.register(*args)
31
+ registration = ProbeRegistration.new(*args)
32
+
33
+ if is_available?(registration.klass_name)
34
+ installed[registration.klass_name] = registration
35
+ registration.install
36
+ else
37
+ register_require_hook(registration)
38
+ end
39
+ end
40
+
41
+ def self.require_hook(require_path)
42
+ return unless Skylight.native?
43
+
44
+ registration = lookup_by_require_path(require_path)
45
+ return unless registration
46
+
47
+ # Double check constant is available
48
+ if is_available?(registration.klass_name)
49
+ installed[registration.klass_name] = registration
50
+ registration.install
51
+
52
+ # Don't need this to be called again
53
+ unregister_require_hook(registration)
54
+ end
55
+ end
56
+
57
+ def self.register_require_hook(registration)
58
+ registration.require_paths.each do |p|
59
+ require_hooks[p] = registration
60
+ end
61
+ end
62
+
63
+ def self.unregister_require_hook(registration)
64
+ registration.require_paths.each do |p|
65
+ require_hooks.delete(p)
66
+ end
67
+ end
68
+
69
+ def self.lookup_by_require_path(require_path)
70
+ require_hooks[require_path]
71
+ end
72
+ end
73
+ end
74
+
75
+ # Allow hooking require
76
+ # @api private
77
+ module ::Kernel
78
+ alias require_without_sk require
79
+
80
+ def require(name)
81
+ ret = require_without_sk(name)
82
+
83
+ begin
84
+ Skylight::Probes.require_hook(name)
85
+ rescue Exception
86
+ # FIXME: Log these errors
87
+ end
88
+
89
+ ret
90
+ end
91
+ end
@@ -0,0 +1,25 @@
1
+ module Skylight
2
+ module Probes
3
+ module Excon
4
+ class Probe
5
+ def install
6
+ if defined?(::Excon::Middleware)
7
+ # Don't require until installation since it depends on Excon being loaded
8
+ require 'skylight/probes/excon/middleware'
9
+
10
+ idx = ::Excon.defaults[:middlewares].index(::Excon::Middleware::Instrumentor)
11
+
12
+ # TODO: Handle possibility of idx being nil
13
+ ::Excon.defaults[:middlewares].insert(idx, Skylight::Probes::Excon::Middleware)
14
+ else
15
+ # Using $stderr here isn't great, but we don't have a logger accessible
16
+ $stderr.puts "[SKYLIGHT] [#{Skylight::VERSION}] The installed version of Excon doesn't " \
17
+ "support Middlewares. The Excon probe will be disabled."
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ register("Excon", "excon", Excon::Probe.new)
24
+ end
25
+ end
@@ -0,0 +1,65 @@
1
+ require 'skylight/formatters/http'
2
+
3
+ module Skylight
4
+ module Probes
5
+ module Excon
6
+ class Middleware < ::Excon::Middleware::Base
7
+
8
+ # This probably won't work since config isn't defined
9
+ include Util::Logging
10
+
11
+ def initialize(*)
12
+ @requests = {}
13
+ super
14
+ end
15
+
16
+ # TODO:
17
+ # - Consider whether a LIFO queue would be sufficient
18
+ # - Check that errors can't be called without a request
19
+
20
+ def request_call(datum)
21
+ begin_instrumentation(datum)
22
+ super
23
+ end
24
+
25
+ def response_call(datum)
26
+ super
27
+ ensure
28
+ end_instrumentation(datum)
29
+ end
30
+
31
+ def error_call(datum)
32
+ super
33
+ ensure
34
+ end_instrumentation(datum)
35
+ end
36
+
37
+ private
38
+
39
+ def begin_instrumentation(datum)
40
+ method = datum[:method].to_s
41
+ scheme = datum[:scheme]
42
+ host = datum[:host]
43
+ # TODO: Maybe don't show other default ports like 443
44
+ port = datum[:port] != 80 ? datum[:port] : nil
45
+ path = datum[:path]
46
+ query = datum[:query]
47
+
48
+ opts = Formatters::HTTP.build_opts(method, scheme, host, port, path, query)
49
+
50
+ @requests[datum.object_id] = Skylight.instrument(opts)
51
+ rescue Exception => e
52
+ error "failed to begin instrumentation for Excon; msg=%s", e.message
53
+ end
54
+
55
+ def end_instrumentation(datum)
56
+ @requests[datum.object_id].done
57
+ @requests.delete(datum)
58
+ rescue Exception => e
59
+ error "failed to end instrumentation for Excon; msg=%s", e.message
60
+ end
61
+
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,44 @@
1
+ require 'skylight/formatters/http'
2
+
3
+ module Skylight
4
+ module Probes
5
+ module NetHTTP
6
+ class Probe
7
+ def install
8
+ Net::HTTP.class_eval do
9
+ alias request_without_sk request
10
+
11
+ def request(req, body = nil, &block)
12
+ unless started?
13
+ return request_without_sk(req, body, &block)
14
+ end
15
+
16
+ method = req.method
17
+
18
+ # req['host'] also includes special handling for default ports
19
+ host, port = req['host'] ? req['host'].split(':') : nil
20
+
21
+ # If we're connected with a persistent socket
22
+ host ||= self.address
23
+ port ||= self.port
24
+
25
+ path = req.path
26
+ scheme = use_ssl? ? "https" : "http"
27
+
28
+ # Contained in the path
29
+ query = nil
30
+
31
+ opts = Formatters::HTTP.build_opts(method, scheme, host, port, path, query)
32
+
33
+ Skylight.instrument(opts) do
34
+ request_without_sk(req, body, &block)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ register("Net::HTTP", "net/http", NetHTTP::Probe.new)
43
+ end
44
+ end
@@ -0,0 +1,30 @@
1
+ module Skylight
2
+ module Probes
3
+ module Redis
4
+ class Probe
5
+ def install
6
+ ::Redis::Client.class_eval do
7
+ alias call_without_sk call
8
+
9
+ def call(command, &block)
10
+ command_name = command[0]
11
+
12
+ return call_without_sk(command, &block) if command_name == :auth
13
+
14
+ opts = {
15
+ category: "db.redis.command",
16
+ title: command_name.upcase.to_s
17
+ }
18
+
19
+ Skylight.instrument(opts) do
20
+ call_without_sk(command, &block)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ register("Redis", "redis", Redis::Probe.new)
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ # Supports 3.12.0+
2
+ module Skylight
3
+ module Probes
4
+ module Sequel
5
+ class Probe
6
+ def install
7
+ require 'sequel/database/logging'
8
+ ::Sequel::Database.class_eval do
9
+ alias log_yield_without_sk log_yield
10
+
11
+ def log_yield(sql, args=nil, &block)
12
+ log_yield_without_sk(sql, *args) do
13
+ ::ActiveSupport::Notifications.instrument(
14
+ "sql.sequel",
15
+ sql: sql,
16
+ name: "SQL",
17
+ binds: args
18
+ ) do
19
+ block.call
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ register("Sequel", "sequel", Sequel::Probe.new)
29
+ end
30
+ end
@@ -0,0 +1,74 @@
1
+ module Skylight
2
+ module Probes
3
+ module Sinatra
4
+ class Probe
5
+ def install
6
+ class << ::Sinatra::Base
7
+ alias build_without_sk build
8
+ alias compile_without_sk! compile!
9
+
10
+ def compile!(verb, path, *args, &block)
11
+ compile_without_sk!(verb, path, *args, &block).tap do |_, _, _, wrapper|
12
+ # Deal with the situation where the path is a regex, and the default behavior
13
+ # of Ruby stringification produces an unreadable mess
14
+ if path.is_a?(Regexp)
15
+ human_readable = "<sk-regex>%r{#{path.source}}</sk-regex>"
16
+ wrapper.instance_variable_set(:@route_name, "#{verb} #{human_readable}")
17
+ else
18
+ wrapper.instance_variable_set(:@route_name, "#{verb} #{path}")
19
+ end
20
+
21
+ # Newer versions of Sinatra populate env['sinatra.route']. Polyfill older
22
+ # versions in a targeted but hackish way.
23
+ if ::Sinatra::VERSION < '1.4.0'
24
+ def wrapper.[](app, args)
25
+ app.env['sinatra.route'] = @route_name
26
+ super
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ def build(*args, &block)
33
+ self.use Skylight::Middleware
34
+ build_without_sk(*args, &block)
35
+ end
36
+ end
37
+
38
+ ::Sinatra::Base.class_eval do
39
+ alias dispatch_without_sk! dispatch!
40
+ alias compile_template_without_sk compile_template
41
+
42
+ def dispatch!(*args, &block)
43
+ dispatch_without_sk!(*args, &block).tap do
44
+ instrumenter = Skylight::Instrumenter.instance
45
+ next unless instrumenter
46
+ trace = instrumenter.current_trace
47
+ next unless trace
48
+
49
+ # Set the endpoint name to the route name
50
+ route = env['sinatra.route']
51
+ trace.endpoint = route if route
52
+ end
53
+ end
54
+
55
+ def compile_template(engine, data, options, *args, &block)
56
+ # Pass along a useful "virtual path" to Tilt. The Tilt probe will handle
57
+ # instrumenting correctly.
58
+ case data
59
+ when Symbol
60
+ options[:sky_virtual_path] = data.to_s
61
+ else
62
+ options[:sky_virtual_path] = "Inline template (#{engine})"
63
+ end
64
+
65
+ compile_template_without_sk(engine, data, options, *args, &block)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ register("Sinatra::Base", "sinatra/base", Sinatra::Probe.new)
73
+ end
74
+ end
@@ -0,0 +1,27 @@
1
+ # Supports 0.2+, though Sinatra doesn't support 2.0, and Rails doesn't work with older versions
2
+ module Skylight
3
+ module Probes
4
+ module Tilt
5
+ class Probe
6
+ def install
7
+ ::Tilt::Template.class_eval do
8
+ alias render_without_sk render
9
+
10
+ def render(*args, &block)
11
+ opts = {
12
+ category: "view.render.template",
13
+ title: options[:sky_virtual_path] || "Unknown template name"
14
+ }
15
+
16
+ Skylight.instrument(opts) do
17
+ render_without_sk(*args, &block)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ register("Tilt::Template", "tilt/template", Tilt::Probe.new)
26
+ end
27
+ end
@@ -0,0 +1,122 @@
1
+ require 'skylight'
2
+ require 'rails'
3
+
4
+ module Skylight
5
+ # @api private
6
+ class Railtie < Rails::Railtie
7
+ config.skylight = ActiveSupport::OrderedOptions.new
8
+
9
+ # The environments in which skylight should be enabled
10
+ config.skylight.environments = ['production']
11
+
12
+ # The path to the configuration file
13
+ config.skylight.config_path = "config/skylight.yml"
14
+
15
+ # The probes to load
16
+ # net_http is on by default
17
+ # Also available: excon, redis
18
+ config.skylight.probes = ['net_http']
19
+
20
+ initializer 'skylight.configure' do |app|
21
+ # Load probes even when agent is inactive to catch probe related bugs sooner
22
+ load_probes
23
+
24
+ config = load_skylight_config(app)
25
+
26
+ if activate?
27
+ if config
28
+ if Instrumenter.start!(config)
29
+ app.middleware.insert 0, Middleware, config: config
30
+ Rails.logger.info "[SKYLIGHT] [#{Skylight::VERSION}] Skylight agent enabled"
31
+ else
32
+ Rails.logger.info "[SKYLIGHT] [#{Skylight::VERSION}] Unable to start"
33
+ end
34
+ end
35
+ elsif Rails.env.development?
36
+ log_warning config, "[SKYLIGHT] [#{Skylight::VERSION}] Running Skylight in development mode. No data will be reported until you deploy your app.\n" \
37
+ "(To disable this message, set `alert_log_file` in your config.)"
38
+ elsif !Rails.env.test?
39
+ log_warning config, "[SKYLIGHT] [#{Skylight::VERSION}] You are running in the #{Rails.env} environment but haven't added it to config.skylight.environments, so no data will be sent to skylight.io."
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def log_warning(config, msg)
46
+ if config
47
+ config.alert_logger.warn(msg)
48
+ else
49
+ Rails.logger.warn(msg)
50
+ end
51
+ end
52
+
53
+ def existent_paths(paths)
54
+ paths.respond_to?(:existent) ? paths.existent : paths.select { |f| File.exists?(f) }
55
+ end
56
+
57
+ def load_skylight_config(app)
58
+ path = config_path(app)
59
+ path = nil unless File.exist?(path)
60
+
61
+ unless tmp = app.config.paths['tmp'].first
62
+ Rails.logger.error "[SKYLIGHT] [#{Skylight::VERSION}] tmp directory missing from rails configuration"
63
+ return nil
64
+ end
65
+
66
+ config = Config.load(file: path, environment: Rails.env.to_s)
67
+ config['root'] = Rails.root
68
+
69
+ configure_logging(config, app)
70
+
71
+ config['daemon.sockdir_path'] ||= tmp
72
+ config['normalizers.render.view_paths'] = existent_paths(app.config.paths["app/views"]) + [Rails.root.to_s]
73
+ config.validate!
74
+ config
75
+
76
+ rescue ConfigError => e
77
+ Rails.logger.error "[SKYLIGHT] [#{Skylight::VERSION}] #{e.message}; disabling Skylight agent"
78
+ nil
79
+ end
80
+
81
+ def configure_logging(config, app)
82
+ if logger = app.config.skylight.logger
83
+ config.logger = logger
84
+ else
85
+ # Configure the log file destination
86
+ if log_file = app.config.skylight.log_file
87
+ config['log_file'] = log_file
88
+ elsif !config.key?('log_file')
89
+ config['log_file'] = File.join(Rails.root, 'log/skylight.log')
90
+ end
91
+
92
+ # Configure the log level
93
+ if level = app.config.skylight.log_level
94
+ config['log_level'] = level
95
+ elsif !config.key?('log_level')
96
+ if level = app.config.log_level
97
+ config['log_level'] = level
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ def config_path(app)
104
+ File.expand_path(config.skylight.config_path, app.root)
105
+ end
106
+
107
+ def environments
108
+ Array(config.skylight.environments).map { |e| e && e.to_s }.compact
109
+ end
110
+
111
+ def activate?
112
+ environments.include?(Rails.env.to_s)
113
+ end
114
+
115
+ def load_probes
116
+ probes = config.skylight.probes || []
117
+ probes.each do |p|
118
+ require "skylight/probes/#{p}"
119
+ end
120
+ end
121
+ end
122
+ end