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.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +399 -336
  3. data/CLA.md +1 -1
  4. data/CONTRIBUTING.md +2 -8
  5. data/LICENSE.md +7 -17
  6. data/README.md +1 -1
  7. data/ext/extconf.rb +45 -56
  8. data/ext/libskylight.yml +10 -6
  9. data/ext/skylight_native.c +22 -99
  10. data/lib/skylight.rb +201 -14
  11. data/lib/skylight/api.rb +32 -21
  12. data/lib/skylight/cli.rb +48 -46
  13. data/lib/skylight/cli/doctor.rb +62 -63
  14. data/lib/skylight/cli/helpers.rb +19 -19
  15. data/lib/skylight/cli/merger.rb +142 -138
  16. data/lib/skylight/config.rb +634 -199
  17. data/lib/skylight/deprecation.rb +17 -0
  18. data/lib/skylight/errors.rb +23 -9
  19. data/lib/skylight/extensions.rb +95 -0
  20. data/lib/skylight/extensions/source_location.rb +291 -0
  21. data/lib/skylight/formatters/http.rb +18 -0
  22. data/lib/skylight/gc.rb +99 -0
  23. data/lib/skylight/helpers.rb +81 -36
  24. data/lib/skylight/instrumenter.rb +336 -18
  25. data/lib/skylight/middleware.rb +134 -1
  26. data/lib/skylight/native.rb +60 -12
  27. data/lib/skylight/native_ext_fetcher.rb +13 -14
  28. data/lib/skylight/normalizers.rb +157 -0
  29. data/lib/skylight/normalizers/action_controller/process_action.rb +68 -0
  30. data/lib/skylight/normalizers/action_controller/send_file.rb +51 -0
  31. data/lib/skylight/normalizers/action_dispatch/process_middleware.rb +22 -0
  32. data/lib/skylight/normalizers/action_dispatch/route_set.rb +27 -0
  33. data/lib/skylight/normalizers/action_view/render_collection.rb +24 -0
  34. data/lib/skylight/normalizers/action_view/render_layout.rb +25 -0
  35. data/lib/skylight/normalizers/action_view/render_partial.rb +23 -0
  36. data/lib/skylight/normalizers/action_view/render_template.rb +23 -0
  37. data/lib/skylight/normalizers/active_job/perform.rb +90 -0
  38. data/lib/skylight/normalizers/active_model_serializers/render.rb +32 -0
  39. data/lib/skylight/normalizers/active_record/instantiation.rb +16 -0
  40. data/lib/skylight/normalizers/active_record/sql.rb +12 -0
  41. data/lib/skylight/normalizers/active_storage.rb +28 -0
  42. data/lib/skylight/normalizers/active_support/cache.rb +11 -0
  43. data/lib/skylight/normalizers/active_support/cache_clear.rb +16 -0
  44. data/lib/skylight/normalizers/active_support/cache_decrement.rb +16 -0
  45. data/lib/skylight/normalizers/active_support/cache_delete.rb +16 -0
  46. data/lib/skylight/normalizers/active_support/cache_exist.rb +16 -0
  47. data/lib/skylight/normalizers/active_support/cache_fetch_hit.rb +16 -0
  48. data/lib/skylight/normalizers/active_support/cache_generate.rb +16 -0
  49. data/lib/skylight/normalizers/active_support/cache_increment.rb +16 -0
  50. data/lib/skylight/normalizers/active_support/cache_read.rb +16 -0
  51. data/lib/skylight/normalizers/active_support/cache_read_multi.rb +16 -0
  52. data/lib/skylight/normalizers/active_support/cache_write.rb +16 -0
  53. data/lib/skylight/normalizers/coach/handler_finish.rb +44 -0
  54. data/lib/skylight/normalizers/coach/middleware_finish.rb +33 -0
  55. data/lib/skylight/normalizers/couch_potato/query.rb +20 -0
  56. data/lib/skylight/normalizers/data_mapper/sql.rb +12 -0
  57. data/lib/skylight/normalizers/default.rb +24 -0
  58. data/lib/skylight/normalizers/elasticsearch/request.rb +20 -0
  59. data/lib/skylight/normalizers/faraday/request.rb +38 -0
  60. data/lib/skylight/normalizers/grape/endpoint.rb +28 -0
  61. data/lib/skylight/normalizers/grape/endpoint_render.rb +25 -0
  62. data/lib/skylight/normalizers/grape/endpoint_run.rb +39 -0
  63. data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +20 -0
  64. data/lib/skylight/normalizers/grape/format_response.rb +20 -0
  65. data/lib/skylight/normalizers/graphiti/render.rb +22 -0
  66. data/lib/skylight/normalizers/graphiti/resolve.rb +31 -0
  67. data/lib/skylight/normalizers/graphql/base.rb +127 -0
  68. data/lib/skylight/normalizers/render.rb +79 -0
  69. data/lib/skylight/normalizers/sequel/sql.rb +12 -0
  70. data/lib/skylight/normalizers/shrine.rb +32 -0
  71. data/lib/skylight/normalizers/sql.rb +45 -0
  72. data/lib/skylight/probes.rb +173 -0
  73. data/lib/skylight/probes/action_controller.rb +52 -0
  74. data/lib/skylight/probes/action_dispatch.rb +2 -0
  75. data/lib/skylight/probes/action_dispatch/request_id.rb +33 -0
  76. data/lib/skylight/probes/action_dispatch/routing/route_set.rb +30 -0
  77. data/lib/skylight/probes/action_view.rb +42 -0
  78. data/lib/skylight/probes/active_job.rb +27 -0
  79. data/lib/skylight/probes/active_job_enqueue.rb +35 -0
  80. data/lib/skylight/probes/active_model_serializers.rb +50 -0
  81. data/lib/skylight/probes/delayed_job.rb +144 -0
  82. data/lib/skylight/probes/elasticsearch.rb +36 -0
  83. data/lib/skylight/probes/excon.rb +25 -0
  84. data/lib/skylight/probes/excon/middleware.rb +65 -0
  85. data/lib/skylight/probes/faraday.rb +23 -0
  86. data/lib/skylight/probes/graphql.rb +38 -0
  87. data/lib/skylight/probes/httpclient.rb +44 -0
  88. data/lib/skylight/probes/middleware.rb +135 -0
  89. data/lib/skylight/probes/mongo.rb +156 -0
  90. data/lib/skylight/probes/mongoid.rb +13 -0
  91. data/lib/skylight/probes/net_http.rb +54 -0
  92. data/lib/skylight/probes/redis.rb +51 -0
  93. data/lib/skylight/probes/sequel.rb +29 -0
  94. data/lib/skylight/probes/sinatra.rb +66 -0
  95. data/lib/skylight/probes/sinatra_add_middleware.rb +10 -10
  96. data/lib/skylight/probes/tilt.rb +25 -0
  97. data/lib/skylight/railtie.rb +157 -27
  98. data/lib/skylight/sidekiq.rb +47 -0
  99. data/lib/skylight/subscriber.rb +108 -0
  100. data/lib/skylight/test.rb +151 -0
  101. data/lib/skylight/trace.rb +325 -22
  102. data/lib/skylight/user_config.rb +58 -0
  103. data/lib/skylight/util.rb +12 -0
  104. data/lib/skylight/util/allocation_free.rb +26 -0
  105. data/lib/skylight/util/clock.rb +57 -0
  106. data/lib/skylight/util/component.rb +22 -22
  107. data/lib/skylight/util/deploy.rb +16 -21
  108. data/lib/skylight/util/gzip.rb +20 -0
  109. data/lib/skylight/util/http.rb +106 -113
  110. data/lib/skylight/util/instrumenter_method.rb +26 -0
  111. data/lib/skylight/util/logging.rb +136 -0
  112. data/lib/skylight/util/lru_cache.rb +36 -0
  113. data/lib/skylight/util/platform.rb +1 -5
  114. data/lib/skylight/util/ssl.rb +1 -25
  115. data/lib/skylight/vendor/cli/thor/rake_compat.rb +1 -1
  116. data/lib/skylight/version.rb +5 -1
  117. data/lib/skylight/vm/gc.rb +60 -0
  118. metadata +126 -13
@@ -0,0 +1,13 @@
1
+ module Skylight
2
+ module Probes
3
+ module Mongoid
4
+ class Probe
5
+ def install
6
+ Skylight::Probes.probe(:mongo)
7
+ end
8
+ end
9
+ end
10
+
11
+ register(:mongoid, "Mongoid", "mongoid", Mongoid::Probe.new)
12
+ end
13
+ end
@@ -0,0 +1,54 @@
1
+ require "skylight/formatters/http"
2
+
3
+ module Skylight
4
+ module Probes
5
+ module NetHTTP
6
+ module Instrumentation
7
+ def request(req, *)
8
+ return super if !started? || Probes::NetHTTP::Probe.disabled?
9
+
10
+ method = req.method
11
+
12
+ # req['host'] also includes special handling for default ports
13
+ host, port = req["host"] ? req["host"].split(":") : nil
14
+
15
+ # If we're connected with a persistent socket
16
+ host ||= address
17
+
18
+ path = req.path
19
+ scheme = use_ssl? ? "https" : "http"
20
+
21
+ # Contained in the path
22
+ query = nil
23
+
24
+ opts = Formatters::HTTP.build_opts(method, scheme, host, port, path, query)
25
+
26
+ Skylight.instrument(opts) { super }
27
+ end
28
+ end
29
+
30
+ # Probe for instrumenting Net::HTTP requests. Works by monkeypatching the default Net::HTTP#request method.
31
+ class Probe
32
+ DISABLED_KEY = :__skylight_net_http_disabled
33
+
34
+ def self.disable
35
+ state_was = Thread.current[DISABLED_KEY]
36
+ Thread.current[DISABLED_KEY] = true
37
+ yield
38
+ ensure
39
+ Thread.current[DISABLED_KEY] = state_was
40
+ end
41
+
42
+ def self.disabled?
43
+ !!Thread.current[DISABLED_KEY]
44
+ end
45
+
46
+ def install
47
+ Net::HTTP.prepend(Instrumentation)
48
+ end
49
+ end
50
+ end
51
+
52
+ register(:net_http, "Net::HTTP", "net/http", NetHTTP::Probe.new)
53
+ end
54
+ end
@@ -0,0 +1,51 @@
1
+ module Skylight
2
+ module Probes
3
+ module Redis
4
+ # Unfortunately, because of the nature of pipelining, there's no way for us to
5
+ # give a time breakdown on the individual items.
6
+
7
+ PIPELINED_OPTS = { category: "db.redis.pipelined".freeze, title: "PIPELINE".freeze, internal: true }.freeze
8
+
9
+ MULTI_OPTS = { category: "db.redis.multi".freeze, title: "MULTI".freeze, internal: true }.freeze
10
+
11
+ module ClientInstrumentation
12
+ def call(command, *)
13
+ command_name = command[0]
14
+
15
+ return super if command_name == :auth
16
+
17
+ opts = { category: "db.redis.command", title: command_name.upcase.to_s, internal: true }
18
+
19
+ Skylight.instrument(opts) { super }
20
+ end
21
+ end
22
+
23
+ module Instrumentation
24
+ def pipelined(*)
25
+ Skylight.instrument(PIPELINED_OPTS) { super }
26
+ end
27
+
28
+ def multi(*)
29
+ Skylight.instrument(MULTI_OPTS) { super }
30
+ end
31
+ end
32
+
33
+ class Probe
34
+ def install
35
+ version = defined?(::Redis::VERSION) ? Gem::Version.new(::Redis::VERSION) : nil
36
+
37
+ if !version || version < Gem::Version.new("3.0.0")
38
+ Skylight.error "The installed version of Redis doesn't support Middlewares. " \
39
+ "At least version 3.0.0 is required."
40
+ return
41
+ end
42
+
43
+ ::Redis::Client.prepend(ClientInstrumentation)
44
+ ::Redis.prepend(Instrumentation)
45
+ end
46
+ end
47
+ end
48
+
49
+ register(:redis, "Redis", "redis", Redis::Probe.new)
50
+ end
51
+ end
@@ -0,0 +1,29 @@
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
+
9
+ method_name = ::Sequel::Database.method_defined?(:log_connection_yield) ? "log_connection_yield" : "log_yield"
10
+
11
+ mod =
12
+ Module.new do
13
+ define_method method_name do |sql, *args, &block|
14
+ super(sql, *args) do
15
+ ::ActiveSupport::Notifications.instrument("sql.sequel", sql: sql, name: "SQL", binds: args) do
16
+ block.call
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ ::Sequel::Database.prepend(mod)
23
+ end
24
+ end
25
+ end
26
+
27
+ register(:sequel, "Sequel", "sequel", Sequel::Probe.new)
28
+ end
29
+ end
@@ -0,0 +1,66 @@
1
+ module Skylight
2
+ module Probes
3
+ module Sinatra
4
+ module ClassInstrumentation
5
+ def compile!(verb, path, *)
6
+ super.tap do |_, _, keys_or_wrapper, wrapper|
7
+ wrapper ||= keys_or_wrapper
8
+
9
+ # Deal with the situation where the path is a regex, and the default behavior
10
+ # of Ruby stringification produces an unreadable mess
11
+ if path.is_a?(Regexp)
12
+ human_readable = "<sk-regex>%r{#{path.source}}</sk-regex>"
13
+ wrapper.instance_variable_set(:@route_name, "#{verb} #{human_readable}")
14
+ else
15
+ wrapper.instance_variable_set(:@route_name, "#{verb} #{path}")
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ module Instrumentation
22
+ def dispatch!(*)
23
+ super.tap do
24
+ if (trace = Skylight.instrumenter&.current_trace) && (route = env["sinatra.route"])
25
+ # Include the app's mount point (if available)
26
+ script_name = trace.instrumenter.config.sinatra_route_prefixes? && env["SCRIPT_NAME"]
27
+
28
+ trace.endpoint =
29
+ if script_name && !script_name.empty?
30
+ verb, path = route.split(" ", 2)
31
+ "#{verb} [#{script_name}]#{path}"
32
+ else
33
+ route
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ def compile_template(engine, data, options, *)
40
+ super.tap do |template|
41
+ if defined?(::Tilt::Template) && template.is_a?(::Tilt::Template)
42
+ # Pass along a useful "virtual path" to Tilt. The Tilt probe will handle
43
+ # instrumenting correctly.
44
+ virtual_path = data.is_a?(Symbol) ? data.to_s : "Inline template (#{engine})"
45
+ template.instance_variable_set(:@__sky_virtual_path, virtual_path)
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ class Probe
52
+ def install
53
+ if ::Sinatra::VERSION < "1.4.0"
54
+ Skylight.error "Sinatra must be version 1.4.0 or greater."
55
+ return
56
+ end
57
+
58
+ ::Sinatra::Base.singleton_class.prepend(ClassInstrumentation)
59
+ ::Sinatra::Base.prepend(Instrumentation)
60
+ end
61
+ end
62
+ end
63
+
64
+ register(:sinatra, "Sinatra::Base", "sinatra/base", Sinatra::Probe.new)
65
+ end
66
+ end
@@ -1,20 +1,20 @@
1
1
  module Skylight
2
2
  module Probes
3
3
  module Sinatra
4
- class Probe
5
- def install
6
- class << ::Sinatra::Base
7
- alias_method :build_without_sk, :build
4
+ module Instrumentation
5
+ def build(*)
6
+ use Skylight::Middleware
7
+ super
8
+ end
9
+ end
8
10
 
9
- def build(*args, &block)
10
- use Skylight::Middleware
11
- build_without_sk(*args, &block)
12
- end
13
- end
11
+ class AddMiddlewareProbe
12
+ def install
13
+ ::Sinatra::Base.singleton_class.prepend(Instrumentation)
14
14
  end
15
15
  end
16
16
  end
17
17
 
18
- Skylight::Core::Probes.register(:sinatra_add_middleware, "Sinatra::Base", "sinatra/base", Sinatra::Probe.new)
18
+ register(:sinatra_add_middleware, "Sinatra::Base", "sinatra/base", Sinatra::AddMiddlewareProbe.new)
19
19
  end
20
20
  end
@@ -0,0 +1,25 @@
1
+ # Should support 0.2+, though not tested against older versions
2
+ module Skylight
3
+ module Probes
4
+ module Tilt
5
+ module Instrumentation
6
+ def render(*args, &block)
7
+ opts = {
8
+ category: "view.render.template",
9
+ title: @__sky_virtual_path || options[:sky_virtual_path] || basename || "Unknown template name"
10
+ }
11
+
12
+ Skylight.instrument(opts) { super(*args, &block) }
13
+ end
14
+ end
15
+
16
+ class Probe
17
+ def install
18
+ ::Tilt::Template.prepend(Instrumentation)
19
+ end
20
+ end
21
+ end
22
+
23
+ register(:tilt, "Tilt::Template", "tilt/template", Tilt::Probe.new)
24
+ end
25
+ end
@@ -1,14 +1,9 @@
1
- require "skylight/core/railtie"
1
+ require "skylight"
2
+ require "rails"
2
3
 
3
4
  module Skylight
5
+ # @api private
4
6
  class Railtie < Rails::Railtie
5
- include Skylight::Core::Railtie
6
-
7
- # rubocop:disable Style/SingleLineMethods, Layout/EmptyLineBetweenDefs
8
- def self.config_class; Skylight::Config end
9
- def self.middleware_class; Skylight::Middleware end
10
- # rubocop:enable Style/SingleLineMethods, Layout/EmptyLineBetweenDefs
11
-
12
7
  config.skylight = ActiveSupport::OrderedOptions.new
13
8
 
14
9
  # The environments in which skylight should be enabled
@@ -33,34 +28,169 @@ module Skylight
33
28
 
34
29
  private
35
30
 
36
- def activate?(sk_config)
37
- return false unless super && sk_config
38
- show_worker_activation_warning(sk_config)
39
- true
40
- end
31
+ # We must have an opt-in signal
32
+ def show_worker_activation_warning(sk_config)
33
+ reasons = []
34
+ reasons << "the 'active_job' probe is enabled" if sk_rails_config.probes.include?("active_job")
35
+ reasons << "the 'delayed_job' probe is enabled" if sk_rails_config.probes.include?("delayed_job")
36
+ reasons << "SKYLIGHT_ENABLE_SIDEKIQ is set" if sk_config.enable_sidekiq?
37
+
38
+ return if reasons.empty?
39
+
40
+ sk_config.logger.warn("Activating Skylight for Background Jobs because #{reasons.to_sentence}")
41
+ end
42
+
43
+ def log_prefix
44
+ "[SKYLIGHT] [#{Skylight::VERSION}]"
45
+ end
46
+
47
+ def development_warning
48
+ "#{log_prefix} Running Skylight in development mode. No data will be reported until you deploy your app.\n" \
49
+ "(To disable this message for all local apps, run `skylight disable_dev_warning`.)"
50
+ end
41
51
 
42
- # We must have an opt-in signal
43
- def show_worker_activation_warning(sk_config)
44
- reasons = []
45
- reasons << "the 'active_job' probe is enabled" if sk_rails_config.probes.include?("active_job")
46
- reasons << "the 'delayed_job' probe is enabled" if sk_rails_config.probes.include?("delayed_job")
47
- reasons << "SKYLIGHT_ENABLE_SIDEKIQ is set" if sk_config.enable_sidekiq?
52
+ def run_initializer(app)
53
+ # Load probes even when agent is inactive to catch probe related bugs sooner
54
+ load_probes
48
55
 
49
- return if reasons.empty?
56
+ config = load_skylight_config(app)
50
57
 
51
- sk_config.logger.warn("Activating Skylight for Background Jobs because #{reasons.to_sentence}")
58
+ if activate?(config)
59
+ if config
60
+ if Skylight.start!(config)
61
+ set_middleware_position(app, config)
62
+ Rails.logger.info "#{log_prefix} Skylight agent enabled"
63
+ else
64
+ Rails.logger.info "#{log_prefix} Unable to start, see the Skylight logs for more details"
65
+ end
66
+ end
67
+ elsif Rails.env.development?
68
+ log_warning config, development_warning unless config.user_config.disable_dev_warning?
69
+ elsif !Rails.env.test?
70
+ unless config.user_config.disable_env_warning?
71
+ log_warning config,
72
+ "#{log_prefix} You are running in the #{Rails.env} environment but haven't added it " \
73
+ "to config.skylight.environments, so no data will be sent to Skylight servers."
74
+ end
52
75
  end
76
+ rescue Skylight::ConfigError => e
77
+ Rails.logger.error "#{log_prefix} #{e.message}; disabling Skylight agent"
78
+ end
53
79
 
54
- def development_warning
55
- super + "\n(To disable this message for all local apps, run `skylight disable_dev_warning`.)"
80
+ def log_warning(config, msg)
81
+ config ? config.alert_logger.warn(msg) : Rails.logger.warn(msg)
82
+ end
83
+
84
+ def existent_paths(paths)
85
+ paths.respond_to?(:existent) ? paths.existent : paths.select { |f| File.exist?(f) }
86
+ end
87
+
88
+ def load_skylight_config(app)
89
+ path = config_path(app)
90
+ path = nil unless File.exist?(path)
91
+
92
+ unless (tmp = app.config.paths["tmp"].first)
93
+ Rails.logger.error "#{log_prefix} tmp directory missing from rails configuration"
94
+ return nil
56
95
  end
57
96
 
58
- def load_skylight_config(app)
59
- super.tap do |sk_config|
60
- if sk_config && sk_config[:report_rails_env]
61
- sk_config[:env] ||= Rails.env.to_s
97
+ config = Config.load(file: path, priority_key: Rails.env.to_s)
98
+ config[:root] = Rails.root
99
+
100
+ configure_logging(config, app)
101
+
102
+ config[:'daemon.sockdir_path'] ||= tmp
103
+ config[:'normalizers.render.view_paths'] = existent_paths(app.config.paths["app/views"]) + [Rails.root.to_s]
104
+
105
+ config[:env] ||= Rails.env.to_s if config[:report_rails_env]
106
+
107
+ config
108
+ end
109
+
110
+ def configure_logging(config, app)
111
+ if (logger = sk_rails_config(app).logger)
112
+ config.logger = logger
113
+ else
114
+ # Configure the log file destination
115
+ if (log_file = sk_rails_config(app).log_file)
116
+ config["log_file"] = log_file
117
+ end
118
+
119
+ if (native_log_file = sk_rails_config(app).native_log_file)
120
+ config["native_log_file"] = native_log_file
121
+ end
122
+
123
+ config["log_file"] = File.join(Rails.root, "log/skylight.log") if !config.key?("log_file") && !config.on_heroku?
124
+
125
+ # Configure the log level
126
+ if (level = sk_rails_config(app).log_level)
127
+ config["log_level"] = level
128
+ elsif !config.key?("log_level")
129
+ if (level = app.config.log_level)
130
+ config["log_level"] = level
62
131
  end
63
132
  end
64
133
  end
134
+ end
135
+
136
+ def config_path(app)
137
+ File.expand_path(sk_rails_config.config_path, app.root)
138
+ end
139
+
140
+ def environments
141
+ Array(sk_rails_config.environments).map { |e| e&.to_s }.compact
142
+ end
143
+
144
+ def activate?(sk_config)
145
+ return false unless sk_config
146
+
147
+ key = "SKYLIGHT_ENABLED"
148
+ activate = ENV.key?(key) ? ENV[key] !~ /^false$/i : environments.include?(Rails.env.to_s)
149
+
150
+ show_worker_activation_warning(sk_config) if activate
151
+
152
+ activate
153
+ end
154
+
155
+ def load_probes
156
+ probes = sk_rails_config.probes || []
157
+ Skylight::Probes.probe(*probes)
158
+ end
159
+
160
+ def middleware_position
161
+ if sk_rails_config.middleware_position.is_a?(Hash)
162
+ sk_rails_config.middleware_position.symbolize_keys
163
+ else
164
+ sk_rails_config.middleware_position
165
+ end
166
+ end
167
+
168
+ def insert_middleware(app, config)
169
+ if middleware_position.key?(:after)
170
+ app.middleware.insert_after(middleware_position[:after], Skylight::Middleware, config: config)
171
+ elsif middleware_position.key?(:before)
172
+ app.middleware.insert_before(middleware_position[:before], Skylight::Middleware, config: config)
173
+ else
174
+ raise "The middleware position you have set is invalid. Please be sure " \
175
+ "`config.skylight.middleware_position` is set up correctly."
176
+ end
177
+ end
178
+
179
+ def set_middleware_position(app, config)
180
+ if middleware_position.is_a?(Integer)
181
+ app.middleware.insert middleware_position, Skylight::Middleware, config: config
182
+ elsif middleware_position.is_a?(Hash) && middleware_position.keys.count == 1
183
+ insert_middleware(app, config)
184
+ elsif middleware_position.nil?
185
+ app.middleware.insert 0, Skylight::Middleware, config: config
186
+ else
187
+ raise "The middleware position you have set is invalid. Please be sure " \
188
+ "`config.skylight.middleware_position` is set up correctly."
189
+ end
190
+ end
191
+
192
+ def sk_rails_config(target = self)
193
+ target.config.skylight
194
+ end
65
195
  end
66
196
  end