scout_rails 0.0.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.
- data/.DS_Store +0 -0
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.markdown +29 -0
- data/Rakefile +1 -0
- data/lib/scout_rails.rb +31 -0
- data/lib/scout_rails/agent.rb +316 -0
- data/lib/scout_rails/config.rb +34 -0
- data/lib/scout_rails/environment.rb +86 -0
- data/lib/scout_rails/instruments/active_record_instruments.rb +88 -0
- data/lib/scout_rails/instruments/process/process_cpu.rb +27 -0
- data/lib/scout_rails/instruments/process/process_memory.rb +40 -0
- data/lib/scout_rails/instruments/rails/action_controller_instruments.rb +47 -0
- data/lib/scout_rails/instruments/rails3/action_controller_instruments.rb +35 -0
- data/lib/scout_rails/instruments/sinatra_instruments.rb +34 -0
- data/lib/scout_rails/layaway.rb +77 -0
- data/lib/scout_rails/layaway_file.rb +70 -0
- data/lib/scout_rails/metric_meta.rb +36 -0
- data/lib/scout_rails/metric_stats.rb +45 -0
- data/lib/scout_rails/stack_item.rb +18 -0
- data/lib/scout_rails/store.rb +78 -0
- data/lib/scout_rails/tracer.rb +90 -0
- data/lib/scout_rails/version.rb +3 -0
- data/scout_rails.gemspec +24 -0
- metadata +71 -0
data/.DS_Store
ADDED
|
Binary file
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.markdown
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# ScoutRails
|
|
2
|
+
|
|
3
|
+
A Ruby gem for detailed Rails application performance analysis. Metrics are reported to [Scout](https://scoutapp.com), a hosted server and application monitoring service. For general server monitoring, see our [server monitoring agent](https://github.com/highgroove/scout-client).
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
Install the gem:
|
|
8
|
+
|
|
9
|
+
gem install scout_rails
|
|
10
|
+
|
|
11
|
+
Signup for a [Scout](https://scoutapp.com) account and copy the config file to RAILS_ROOT/config/scout_rails.yml.
|
|
12
|
+
|
|
13
|
+
## Supported Frameworks
|
|
14
|
+
|
|
15
|
+
* Rails 2.2 and greater
|
|
16
|
+
|
|
17
|
+
## Supported Rubies
|
|
18
|
+
|
|
19
|
+
* Ruby 1.8.7
|
|
20
|
+
* Ruby 1.9.2
|
|
21
|
+
|
|
22
|
+
## Supported Application Servers
|
|
23
|
+
|
|
24
|
+
* Phusion Passenger
|
|
25
|
+
* Thin
|
|
26
|
+
* WEBrick
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/scout_rails.rb
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module ScoutRails
|
|
2
|
+
end
|
|
3
|
+
require 'socket'
|
|
4
|
+
require 'set'
|
|
5
|
+
require 'net/http'
|
|
6
|
+
require File.expand_path('../scout_rails/version.rb', __FILE__)
|
|
7
|
+
require File.expand_path('../scout_rails/agent.rb', __FILE__)
|
|
8
|
+
require File.expand_path('../scout_rails/layaway.rb', __FILE__)
|
|
9
|
+
require File.expand_path('../scout_rails/layaway_file.rb', __FILE__)
|
|
10
|
+
require File.expand_path('../scout_rails/config.rb', __FILE__)
|
|
11
|
+
require File.expand_path('../scout_rails/environment.rb', __FILE__)
|
|
12
|
+
require File.expand_path('../scout_rails/metric_meta.rb', __FILE__)
|
|
13
|
+
require File.expand_path('../scout_rails/metric_stats.rb', __FILE__)
|
|
14
|
+
require File.expand_path('../scout_rails/stack_item.rb', __FILE__)
|
|
15
|
+
require File.expand_path('../scout_rails/store.rb', __FILE__)
|
|
16
|
+
require File.expand_path('../scout_rails/tracer.rb', __FILE__)
|
|
17
|
+
require File.expand_path('../scout_rails/instruments/process/process_cpu.rb', __FILE__)
|
|
18
|
+
require File.expand_path('../scout_rails/instruments/process/process_memory.rb', __FILE__)
|
|
19
|
+
|
|
20
|
+
if defined?(Rails) and Rails.respond_to?(:version) and Rails.version =~ /^3/
|
|
21
|
+
module ScoutRails
|
|
22
|
+
class Railtie < Rails::Railtie
|
|
23
|
+
initializer "scout_rails.start" do |app|
|
|
24
|
+
ScoutRails::Agent.instance.start
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
else
|
|
29
|
+
ScoutRails::Agent.instance.start
|
|
30
|
+
end
|
|
31
|
+
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
module ScoutRails
|
|
2
|
+
# The agent gathers performance data from a Ruby application. One Agent instance is created per-Ruby process.
|
|
3
|
+
#
|
|
4
|
+
# Each Agent object creates a worker thread (unless monitoring is disabled or we're forking).
|
|
5
|
+
# The worker thread wakes up every +Agent#period+, merges in-memory metrics w/those saved to disk,
|
|
6
|
+
# saves the merged data to disk, and sends it to the Scout server.
|
|
7
|
+
class Agent
|
|
8
|
+
# Headers passed up with all API requests.
|
|
9
|
+
HTTP_HEADERS = { "Agent-Hostname" => Socket.gethostname }
|
|
10
|
+
DEFAULT_HOST = 'scoutapp.com'
|
|
11
|
+
# see self.instance
|
|
12
|
+
@@instance = nil
|
|
13
|
+
|
|
14
|
+
# Accessors below are for associated classes
|
|
15
|
+
attr_accessor :store
|
|
16
|
+
attr_accessor :layaway
|
|
17
|
+
attr_accessor :config
|
|
18
|
+
attr_accessor :environment
|
|
19
|
+
|
|
20
|
+
attr_accessor :logger
|
|
21
|
+
attr_accessor :log_file # path to the log file
|
|
22
|
+
attr_accessor :options # options passed to the agent when +#start+ is called.
|
|
23
|
+
attr_accessor :metric_lookup # Hash used to lookup metric ids based on their name and scope
|
|
24
|
+
|
|
25
|
+
# Hash of class (values are Sets of method names) that should be instrumented by examining
|
|
26
|
+
# the ActiveRecord call stack.
|
|
27
|
+
attr_accessor :dynamic_instruments
|
|
28
|
+
|
|
29
|
+
# All access to the agent is thru this class method to ensure multiple Agent instances are not initialized per-Ruby process.
|
|
30
|
+
def self.instance(options = {})
|
|
31
|
+
@@instance ||= self.new(options)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Note - this doesn't start instruments or the worker thread. This is handled via +#start+ as we don't
|
|
35
|
+
# want to start the worker thread or install instrumentation if (1) disabled for this environment (2) a worker thread shouldn't
|
|
36
|
+
# be started (when forking).
|
|
37
|
+
def initialize(options = {})
|
|
38
|
+
@started = false
|
|
39
|
+
@options ||= options
|
|
40
|
+
@store = ScoutRails::Store.new
|
|
41
|
+
@layaway = ScoutRails::Layaway.new
|
|
42
|
+
@config = ScoutRails::Config.new(options[:config_path])
|
|
43
|
+
@dynamic_instruments = Hash.new
|
|
44
|
+
@metric_lookup = Hash.new
|
|
45
|
+
@process_cpu=ScoutRails::Instruments::Process::ProcessCpu.new(1) # TODO: the argument is the number of processors
|
|
46
|
+
@process_memory=ScoutRails::Instruments::Process::ProcessMemory.new
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def environment
|
|
50
|
+
@environment ||= ScoutRails::Environment.new
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# This is called via +ScoutRails::Agent.instance.start+ when ScoutRails is required in a Ruby application.
|
|
54
|
+
# It initializes the agent and starts the worker thread (if appropiate).
|
|
55
|
+
def start(options = {})
|
|
56
|
+
@options.merge!(options)
|
|
57
|
+
init_logger
|
|
58
|
+
if !config.settings['monitor'] and !@options[:force]
|
|
59
|
+
logger.warn "Monitoring isn't enabled for the [#{environment.env}] environment."
|
|
60
|
+
return false
|
|
61
|
+
elsif !environment.app_server
|
|
62
|
+
logger.warn "Couldn't find a supported app server. Not starting agent."
|
|
63
|
+
return false
|
|
64
|
+
elsif started?
|
|
65
|
+
logger.warn "Already started agent."
|
|
66
|
+
return false
|
|
67
|
+
end
|
|
68
|
+
@started = true
|
|
69
|
+
logger.info "Starting monitoring. Framework [#{environment.framework}] App Server [#{environment.app_server}]."
|
|
70
|
+
start_instruments
|
|
71
|
+
if !start_worker_thread?
|
|
72
|
+
logger.debug "Not starting worker thread"
|
|
73
|
+
install_passenger_worker_process_event if environment.passenger?
|
|
74
|
+
return
|
|
75
|
+
end
|
|
76
|
+
start_worker_thread
|
|
77
|
+
handle_exit
|
|
78
|
+
log_version_pid
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Placeholder: store metrics locally on exit so those in memory aren't lost. Need to decide
|
|
82
|
+
# whether we'll report these immediately or just store locally and risk having stale data.
|
|
83
|
+
def handle_exit
|
|
84
|
+
if environment.sinatra? || environment.jruby? || environment.rubinius?
|
|
85
|
+
logger.debug "Exit handler not supported"
|
|
86
|
+
else
|
|
87
|
+
at_exit { at_exit { logger.debug "Shutdown!" } }
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def started?
|
|
92
|
+
@started
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def gem_root
|
|
96
|
+
File.expand_path(File.join("..","..",".."), __FILE__)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def init_logger
|
|
100
|
+
@log_file = "#{log_path}/scout_rails.log"
|
|
101
|
+
@logger = Logger.new(@log_file)
|
|
102
|
+
@logger.level = Logger::DEBUG
|
|
103
|
+
def logger.format_message(severity, timestamp, progname, msg)
|
|
104
|
+
prefix = "[#{timestamp.strftime("%m/%d/%y %H:%M:%S %z")} #{Socket.gethostname} (#{$$})] #{severity} : #{msg}\n"
|
|
105
|
+
end
|
|
106
|
+
@logger
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# The worker thread will automatically start UNLESS:
|
|
110
|
+
# * A supported application server isn't detected (example: running via Rails console)
|
|
111
|
+
# * A supported application server is detected, but it forks (Passenger). In this case,
|
|
112
|
+
# the agent is started in the forked process.
|
|
113
|
+
def start_worker_thread?
|
|
114
|
+
!environment.forking? or environment.thin?
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def install_passenger_worker_process_event
|
|
118
|
+
PhusionPassenger.on_event(:starting_worker_process) do |forked|
|
|
119
|
+
logger.debug "Passenger is starting a worker process. Starting worker thread."
|
|
120
|
+
self.class.instance.start_worker_thread
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def log_version_pid
|
|
125
|
+
logger.debug "Scout Agent [#{ScoutRails::VERSION}] Initialized"
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def log_path
|
|
129
|
+
"#{environment.root}/log"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# in seconds, time between when the worker thread wakes up and runs.
|
|
133
|
+
def period
|
|
134
|
+
60
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Every time the worker thread completes, it calls this method
|
|
138
|
+
# to add instruments to selected methods in the AR call stack.
|
|
139
|
+
def add_dynamic_instruments
|
|
140
|
+
dynamic_instruments.each do |class_name,to_instrument|
|
|
141
|
+
klass = class_name.constantize
|
|
142
|
+
klass.class_eval do
|
|
143
|
+
if !klass.respond_to?(:instrument_method)
|
|
144
|
+
include ::ScoutRails::Tracer
|
|
145
|
+
end
|
|
146
|
+
to_instrument.each do |m|
|
|
147
|
+
self.instrument_method(m)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Creates the worker thread. The worker thread is a loop that runs continuously. It sleeps for +Agent#period+ and when it wakes,
|
|
154
|
+
# processes data, either saving it to disk or reporting to Scout.
|
|
155
|
+
def start_worker_thread(connection_options = {})
|
|
156
|
+
logger.debug "Creating worker thread."
|
|
157
|
+
@worker_thread = Thread.new do
|
|
158
|
+
begin
|
|
159
|
+
logger.debug "Starting worker thread, running every #{period} seconds"
|
|
160
|
+
next_time = Time.now + period
|
|
161
|
+
while true do
|
|
162
|
+
now = Time.now
|
|
163
|
+
while now < next_time
|
|
164
|
+
sleep_time = next_time - now
|
|
165
|
+
sleep(sleep_time) if sleep_time > 0
|
|
166
|
+
now = Time.now
|
|
167
|
+
end
|
|
168
|
+
process_metrics
|
|
169
|
+
add_dynamic_instruments
|
|
170
|
+
while next_time <= now
|
|
171
|
+
next_time += period
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
rescue
|
|
175
|
+
logger.debug "Worker Thread Exception!!!!!!!"
|
|
176
|
+
logger.debug $!.message
|
|
177
|
+
logger.debug $!.backtrace
|
|
178
|
+
end
|
|
179
|
+
end # thread new
|
|
180
|
+
logger.debug "Done creating worker thread."
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Writes each payload to a file for auditing.
|
|
184
|
+
def write_to_file(object)
|
|
185
|
+
logger.debug "Writing to file"
|
|
186
|
+
full_path = Pathname.new(RAILS_ROOT+'/log/audit/scout')
|
|
187
|
+
( full_path +
|
|
188
|
+
"#{Time.now.strftime('%Y-%m-%d_%H:%M:%S')}.json" ).open("w") do |f|
|
|
189
|
+
f.puts object.to_json
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Before reporting, lookup metric_id for each MetricMeta. This speeds up
|
|
194
|
+
# reporting on the server-side.
|
|
195
|
+
def add_metric_ids(metrics)
|
|
196
|
+
metrics.each do |meta,stats|
|
|
197
|
+
if metric_id = metric_lookup[meta]
|
|
198
|
+
meta.metric_id = metric_id
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Called from #process_metrics, which is run via the worker thread.
|
|
204
|
+
def run_samplers
|
|
205
|
+
begin
|
|
206
|
+
cpu_util=@process_cpu.run # returns a hash
|
|
207
|
+
logger.debug "Process CPU: #{cpu_util.inspect}"
|
|
208
|
+
store.track!("CPU/Utilization",cpu_util) if cpu_util
|
|
209
|
+
rescue => e
|
|
210
|
+
logger.info "Error reading ProcessCpu"
|
|
211
|
+
logger.debug e.message
|
|
212
|
+
logger.debug e.backtrace.join("\n")
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
begin
|
|
216
|
+
mem_usage=@process_memory.run # returns a single number, in MB
|
|
217
|
+
logger.debug "Process Memory: #{mem_usage}MB"
|
|
218
|
+
store.track!("Memory/Physical",mem_usage) if mem_usage
|
|
219
|
+
rescue => e
|
|
220
|
+
logger.info "Error reading ProcessMemory"
|
|
221
|
+
logger.debug e.message
|
|
222
|
+
logger.debug e.backtrace.join("\n")
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Called in the worker thread. Merges in-memory metrics w/those on disk and reports metrics
|
|
227
|
+
# to the server.
|
|
228
|
+
def process_metrics
|
|
229
|
+
logger.debug "Processing metrics"
|
|
230
|
+
run_samplers
|
|
231
|
+
metrics = layaway.deposit_and_deliver
|
|
232
|
+
if metrics.any?
|
|
233
|
+
add_metric_ids(metrics)
|
|
234
|
+
# for debugging, count the total number of requests
|
|
235
|
+
controller_count = 0
|
|
236
|
+
metrics.each do |meta,stats|
|
|
237
|
+
if meta.metric_name =~ /\AController/
|
|
238
|
+
controller_count += stats.call_count
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
logger.debug "#{config.settings['name']} Delivering metrics for #{controller_count} requests."
|
|
242
|
+
response = post( checkin_uri,
|
|
243
|
+
Marshal.dump(metrics),
|
|
244
|
+
"Content-Type" => "application/json" )
|
|
245
|
+
if response and response.is_a?(Net::HTTPSuccess)
|
|
246
|
+
directives = Marshal.load(response.body)
|
|
247
|
+
self.metric_lookup.merge!(directives[:metric_lookup])
|
|
248
|
+
logger.debug "Metric Cache Size: #{metric_lookup.size}"
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
rescue
|
|
252
|
+
logger.debug "Error on checkin to #{checkin_uri.to_s}"
|
|
253
|
+
logger.debug $!.message
|
|
254
|
+
logger.debug $!.backtrace
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def checkin_uri
|
|
258
|
+
URI.parse("http://#{config.settings['host'] || DEFAULT_HOST}/app/#{config.settings['key']}/checkin.scout?name=#{CGI.escape(config.settings['name'])}")
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def post(url, body, headers = Hash.new)
|
|
262
|
+
response = nil
|
|
263
|
+
request(url) do |connection|
|
|
264
|
+
post = Net::HTTP::Post.new( url.path +
|
|
265
|
+
(url.query ? ('?' + url.query) : ''),
|
|
266
|
+
HTTP_HEADERS.merge(headers) )
|
|
267
|
+
post.body = body
|
|
268
|
+
response=connection.request(post)
|
|
269
|
+
end
|
|
270
|
+
response
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def request(url, &connector)
|
|
274
|
+
response = nil
|
|
275
|
+
http = Net::HTTP.new(url.host, url.port)
|
|
276
|
+
response = http.start(&connector)
|
|
277
|
+
logger.debug "got response: #{response.inspect}"
|
|
278
|
+
case response
|
|
279
|
+
when Net::HTTPSuccess, Net::HTTPNotModified
|
|
280
|
+
logger.debug "/checkin OK"
|
|
281
|
+
when Net::HTTPBadRequest
|
|
282
|
+
logger.warn "/checkin FAILED: The Account Key [#{config.settings['key']}] is invalid."
|
|
283
|
+
else
|
|
284
|
+
logger.debug "/checkin FAILED: #{response.inspect}"
|
|
285
|
+
end
|
|
286
|
+
rescue Exception
|
|
287
|
+
logger.debug "Exception sending request to server: #{$!.message}"
|
|
288
|
+
ensure
|
|
289
|
+
response
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# Loads the instrumention logic.
|
|
293
|
+
def load_instruments
|
|
294
|
+
case environment.framework
|
|
295
|
+
when :rails
|
|
296
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'instruments/rails/action_controller_instruments.rb'))
|
|
297
|
+
when :rails3
|
|
298
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'instruments/rails3/action_controller_instruments.rb'))
|
|
299
|
+
when :sinatra
|
|
300
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'instruments/sinatra_instruments.rb'))
|
|
301
|
+
end
|
|
302
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'instruments/active_record_instruments.rb'))
|
|
303
|
+
rescue
|
|
304
|
+
logger.warn "Exception loading instruments:"
|
|
305
|
+
logger.warn $!.message
|
|
306
|
+
logger.warn $!.backtrace
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# Injects instruments into the Ruby application.
|
|
310
|
+
def start_instruments
|
|
311
|
+
logger.debug "Installing instrumentation"
|
|
312
|
+
load_instruments
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
end # class Agent
|
|
316
|
+
end # module ScoutRails
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module ScoutRails
|
|
2
|
+
class Config
|
|
3
|
+
def initialize(config_path = nil)
|
|
4
|
+
@config_path = config_path
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def settings
|
|
8
|
+
return @settings if @settings
|
|
9
|
+
load_file
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def config_path
|
|
13
|
+
@config_path || File.join(ScoutRails::Agent.instance.environment.root,"config","scout_rails.yml")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def config_file
|
|
17
|
+
File.expand_path(config_path)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def load_file
|
|
21
|
+
if !File.exist?(config_file)
|
|
22
|
+
ScoutRails::Agent.instance.logger.warn "No config file found at [#{config_file}]."
|
|
23
|
+
@settings = {}
|
|
24
|
+
else
|
|
25
|
+
@settings = YAML.load(ERB.new(File.read(config_file)).result(binding))[ScoutRails::Agent.instance.environment.env]
|
|
26
|
+
end
|
|
27
|
+
rescue Exception => e
|
|
28
|
+
ScoutRails::Agent.instance.logger.warn "Unable to load the config file."
|
|
29
|
+
ScoutRails::Agent.instance.logger.warn e.message
|
|
30
|
+
ScoutRails::Agent.instance.logger.warn e.backtrace
|
|
31
|
+
@settings = {}
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Used to retrieve environment information for this application.
|
|
2
|
+
module ScoutRails
|
|
3
|
+
class Environment
|
|
4
|
+
def env
|
|
5
|
+
@env ||= case framework
|
|
6
|
+
when :rails then RAILS_ENV.dup
|
|
7
|
+
when :rails3 then Rails.env
|
|
8
|
+
when :sinatra
|
|
9
|
+
ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def framework
|
|
14
|
+
@framework ||= case
|
|
15
|
+
when defined?(::Rails) && defined?(ActionController)
|
|
16
|
+
if Rails::VERSION::MAJOR < 3
|
|
17
|
+
:rails
|
|
18
|
+
else
|
|
19
|
+
:rails3
|
|
20
|
+
end
|
|
21
|
+
when defined?(::Sinatra) && defined?(::Sinatra::Base) then :sinatra
|
|
22
|
+
else :ruby
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def root
|
|
27
|
+
if framework == :rails
|
|
28
|
+
RAILS_ROOT.to_s
|
|
29
|
+
elsif framework == :rails3
|
|
30
|
+
Rails.root
|
|
31
|
+
elsif framework == :sinatra
|
|
32
|
+
Sinatra::Application.root
|
|
33
|
+
else
|
|
34
|
+
'.'
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def app_server
|
|
39
|
+
@app_server ||= if thin? then :thin
|
|
40
|
+
elsif passenger? then :passenger
|
|
41
|
+
elsif webrick? then :webrick
|
|
42
|
+
else nil
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
### app server related-checks
|
|
47
|
+
|
|
48
|
+
def thin?
|
|
49
|
+
defined?(::Thin) && defined?(::Thin::Server)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Called via +#forking?+ since Passenger forks. Adds an event listener to start the worker thread
|
|
53
|
+
# inside the passenger worker process.
|
|
54
|
+
# Background: http://www.modrails.com/documentation/Users%20guide%20Nginx.html#spawning%5Fmethods%5Fexplained
|
|
55
|
+
def passenger?
|
|
56
|
+
(defined?(::Passenger) && defined?(::Passenger::AbstractServer)) || defined?(::IN_PHUSION_PASSENGER)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def webrick?
|
|
60
|
+
defined?(::WEBrick) && defined?(::WEBrick::VERSION)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# If forking, don't start worker thread in the master process. Since it's started as a Thread, it won't survive
|
|
64
|
+
# the fork.
|
|
65
|
+
def forking?
|
|
66
|
+
passenger?
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
### ruby checks
|
|
70
|
+
|
|
71
|
+
def rubinius?
|
|
72
|
+
RUBY_VERSION =~ /rubinius/i
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def jruby?
|
|
76
|
+
defined?(JRuby)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
### framework checks
|
|
80
|
+
|
|
81
|
+
def sinatra?
|
|
82
|
+
defined?(Sinatra::Application)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end # class Environemnt
|
|
86
|
+
end
|