passenger 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of passenger might be problematic. Click here for more details.
- data/LICENSE +3 -1
- data/Rakefile +17 -12
- data/bin/passenger-config +22 -0
- data/bin/passenger-install-apache2-module +2 -31
- data/bin/passenger-make-enterprisey +66 -0
- data/bin/passenger-memory-stats +192 -0
- data/doc/Users guide.html +150 -66
- data/doc/Users guide.txt +141 -51
- data/doc/cxxapi/ApplicationPoolClientServer_8h-source.html +1 -1
- data/doc/cxxapi/ApplicationPoolServer_8h-source.html +545 -0
- data/doc/cxxapi/ApplicationPool_8h-source.html +1 -1
- data/doc/cxxapi/Application_8h-source.html +1 -1
- data/doc/cxxapi/Configuration_8h-source.html +2 -2
- data/doc/cxxapi/DummySpawnManager_8h-source.html +1 -1
- data/doc/cxxapi/Exceptions_8h-source.html +1 -1
- data/doc/cxxapi/Hooks_8h-source.html +1 -1
- data/doc/cxxapi/Logging_8h-source.html +1 -1
- data/doc/cxxapi/MessageChannel_8h-source.html +210 -205
- data/doc/cxxapi/SpawnManager_8h-source.html +1 -1
- data/doc/cxxapi/StandardApplicationPool_8h-source.html +1 -1
- data/doc/cxxapi/Utils_8h-source.html +1 -1
- data/doc/cxxapi/annotated.html +1 -1
- data/doc/cxxapi/classClient-members.html +30 -0
- data/doc/cxxapi/classClient.html +112 -0
- data/doc/cxxapi/classPassenger_1_1Application-members.html +1 -1
- data/doc/cxxapi/classPassenger_1_1Application.html +1 -1
- data/doc/cxxapi/classPassenger_1_1ApplicationPool-members.html +1 -1
- data/doc/cxxapi/classPassenger_1_1ApplicationPool.html +1 -1
- data/doc/cxxapi/classPassenger_1_1ApplicationPoolServer-members.html +1 -1
- data/doc/cxxapi/classPassenger_1_1ApplicationPoolServer.html +1 -1
- data/doc/cxxapi/classPassenger_1_1Application_1_1Session-members.html +1 -1
- data/doc/cxxapi/classPassenger_1_1Application_1_1Session.html +1 -1
- data/doc/cxxapi/classPassenger_1_1ConfigurationException-members.html +28 -0
- data/doc/cxxapi/classPassenger_1_1ConfigurationException.html +41 -0
- data/doc/cxxapi/classPassenger_1_1DummySpawnManager-members.html +1 -1
- data/doc/cxxapi/classPassenger_1_1DummySpawnManager.html +1 -1
- data/doc/cxxapi/classPassenger_1_1FileNotFoundException-members.html +1 -1
- data/doc/cxxapi/classPassenger_1_1FileNotFoundException.html +1 -1
- data/doc/cxxapi/classPassenger_1_1IOException-members.html +1 -1
- data/doc/cxxapi/classPassenger_1_1IOException.html +1 -1
- data/doc/cxxapi/classPassenger_1_1MessageChannel-members.html +1 -1
- data/doc/cxxapi/classPassenger_1_1MessageChannel.html +1 -1
- data/doc/cxxapi/classPassenger_1_1SpawnException-members.html +1 -1
- data/doc/cxxapi/classPassenger_1_1SpawnException.html +1 -1
- data/doc/cxxapi/classPassenger_1_1SpawnManager-members.html +1 -1
- data/doc/cxxapi/classPassenger_1_1SpawnManager.html +1 -1
- data/doc/cxxapi/classPassenger_1_1StandardApplicationPool-members.html +1 -1
- data/doc/cxxapi/classPassenger_1_1StandardApplicationPool.html +1 -1
- data/doc/cxxapi/classPassenger_1_1SystemException-members.html +1 -1
- data/doc/cxxapi/classPassenger_1_1SystemException.html +1 -1
- data/doc/cxxapi/definitions_8h-source.html +1 -1
- data/doc/cxxapi/files.html +1 -1
- data/doc/cxxapi/functions.html +1 -1
- data/doc/cxxapi/functions_func.html +1 -1
- data/doc/cxxapi/functions_type.html +1 -1
- data/doc/cxxapi/graph_legend.html +1 -1
- data/doc/cxxapi/graph_legend.png +0 -0
- data/doc/cxxapi/group__Configuration.html +3 -3
- data/doc/cxxapi/group__Configuration.png +0 -0
- data/doc/cxxapi/group__Core.html +1 -1
- data/doc/cxxapi/group__Core.png +0 -0
- data/doc/cxxapi/group__Exceptions.html +1 -1
- data/doc/cxxapi/group__Hooks.html +1 -1
- data/doc/cxxapi/group__Hooks.png +0 -0
- data/doc/cxxapi/group__Support.html +1 -1
- data/doc/cxxapi/hierarchy.html +1 -1
- data/doc/cxxapi/inherit__graph__0.png +0 -0
- data/doc/cxxapi/inherit__graph__1.png +0 -0
- data/doc/cxxapi/inherit__graph__10.map +1 -0
- data/doc/cxxapi/inherit__graph__10.md5 +1 -0
- data/doc/cxxapi/inherit__graph__10.png +0 -0
- data/doc/cxxapi/inherit__graph__2.png +0 -0
- data/doc/cxxapi/inherit__graph__3.png +0 -0
- data/doc/cxxapi/inherit__graph__4.png +0 -0
- data/doc/cxxapi/inherit__graph__5.png +0 -0
- data/doc/cxxapi/inherit__graph__6.png +0 -0
- data/doc/cxxapi/inherit__graph__7.png +0 -0
- data/doc/cxxapi/inherit__graph__8.png +0 -0
- data/doc/cxxapi/inherit__graph__9.png +0 -0
- data/doc/cxxapi/inherits.html +1 -1
- data/doc/cxxapi/main.html +1 -1
- data/doc/cxxapi/modules.html +1 -1
- data/doc/cxxapi/structPassenger_1_1AnythingToString-members.html +1 -1
- data/doc/cxxapi/structPassenger_1_1AnythingToString.html +1 -1
- data/doc/cxxapi/structPassenger_1_1AnythingToString_3_01vector_3_01string_01_4_01_4-members.html +1 -1
- data/doc/cxxapi/structPassenger_1_1AnythingToString_3_01vector_3_01string_01_4_01_4.html +1 -1
- data/doc/rdoc/classes/Passenger/RequestHandler.html +84 -74
- data/doc/rdoc/classes/Passenger/SpawnManager.html +54 -49
- data/doc/rdoc/classes/PlatformInfo.html +25 -12
- data/doc/rdoc/created.rid +1 -1
- data/doc/rdoc/files/DEVELOPERS_TXT.html +1 -1
- data/doc/rdoc/files/ext/passenger/native_support_c.html +1 -1
- data/doc/rdoc/files/lib/passenger/abstract_server_rb.html +1 -1
- data/doc/rdoc/files/lib/passenger/application_spawner_rb.html +1 -1
- data/doc/rdoc/files/lib/passenger/dependencies_rb.html +1 -1
- data/doc/rdoc/files/lib/passenger/framework_spawner_rb.html +1 -1
- data/doc/rdoc/files/lib/passenger/platform_info_rb.html +1 -1
- data/doc/rdoc/files/lib/passenger/request_handler_rb.html +1 -1
- data/doc/rdoc/files/lib/passenger/spawn_manager_rb.html +1 -1
- data/ext/apache2/Configuration.h +1 -1
- data/ext/apache2/Hooks.cpp +68 -16
- data/ext/apache2/Logging.cpp +1 -1
- data/ext/apache2/MessageChannel.h +48 -43
- data/ext/passenger/native_support.c +46 -43
- data/lib/passenger/application_spawner.rb +37 -4
- data/lib/passenger/dependencies.rb +5 -1
- data/lib/passenger/framework_spawner.rb +2 -0
- data/lib/passenger/platform_info.rb +32 -17
- data/lib/passenger/request_handler.rb +10 -1
- data/lib/passenger/spawn_manager.rb +14 -8
- data/lib/passenger/templates/error_layout.html.erb +2 -2
- data/test/CxxTestMain.cpp +1 -0
- data/test/MessageChannelTest.cpp +3 -1
- data/test/application_spawner_spec.rb +2 -0
- data/test/framework_spawner_spec.rb +2 -0
- data/test/integration_tests.rb +1 -0
- data/test/spawn_manager_spec.rb +2 -0
- data/test/spawner_privilege_lowering_spec.rb +1 -0
- data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_controller.rb +4 -0
- data/test/stub/minimal-railsapp/vendor/rails/activerecord/lib/active_record.rb +7 -0
- data/test/stub/rails_apps/foobar/config/environments/test.rb +22 -0
- metadata +28 -22
- data/lib/passenger/templates/osx_broken_apache_warning.txt.erb +0 -23
data/LICENSE
CHANGED
@@ -7,7 +7,9 @@ of the application's own licensing terms. The application will not be bound to
|
|
7
7
|
the terms of the GPL in any way. That is, the GPL only applies to Passenger
|
8
8
|
itself, and not to applications that are run through Passenger.
|
9
9
|
|
10
|
-
We also explicitly allow Apache to load the Passenger Apache module
|
10
|
+
We also explicitly allow Apache to load the Passenger Apache module, without
|
11
|
+
Apache or any other loaded modules needing to be released under the terms of
|
12
|
+
the GPL.
|
11
13
|
|
12
14
|
----------------------------------------------------------------------
|
13
15
|
|
data/Rakefile
CHANGED
@@ -27,13 +27,13 @@ require 'passenger/platform_info'
|
|
27
27
|
##### Configuration
|
28
28
|
|
29
29
|
# Don't forget to edit Configuration.h too
|
30
|
-
PACKAGE_VERSION = "1.0.
|
30
|
+
PACKAGE_VERSION = "1.0.2"
|
31
31
|
|
32
32
|
include PlatformInfo
|
33
33
|
APXS2.nil? and raise "Could not find 'apxs' or 'apxs2'."
|
34
34
|
APACHE2CTL.nil? and raise "Could not find 'apachectl' or 'apache2ctl'."
|
35
35
|
HTTPD.nil? and raise "Could not find the Apache web server binary."
|
36
|
-
|
36
|
+
APR_FLAGS.nil? and raise "Could not find Apache Portable Runtime (APR)."
|
37
37
|
|
38
38
|
CXX = "g++"
|
39
39
|
THREADING_FLAGS = "-D_REENTRANT"
|
@@ -101,7 +101,7 @@ end
|
|
101
101
|
##### Apache module
|
102
102
|
|
103
103
|
class APACHE2
|
104
|
-
CXXFLAGS =
|
104
|
+
CXXFLAGS = "-I.. -fPIC -g -DPASSENGER_DEBUG #{APR_FLAGS} #{APXS2_FLAGS} #{CXXFLAGS}"
|
105
105
|
OBJECTS = {
|
106
106
|
'Configuration.o' => %w(Configuration.cpp Configuration.h),
|
107
107
|
'Hooks.o' => %w(Hooks.cpp Hooks.h
|
@@ -128,7 +128,7 @@ subdir 'ext/apache2' do
|
|
128
128
|
#
|
129
129
|
# Oh, and libtool sucks too. Do we even need it anymore in 2008?
|
130
130
|
linkflags = "#{LDFLAGS} #{MULTI_ARCH_FLAGS}"
|
131
|
-
linkflags << " -lstdc++ -lpthread ../boost/src/libboost_thread.a #{
|
131
|
+
linkflags << " -lstdc++ -lpthread ../boost/src/libboost_thread.a #{APR_LIBS}"
|
132
132
|
create_shared_library 'mod_passenger.so',
|
133
133
|
APACHE2::OBJECTS.keys.join(' ') << ' mod_passenger.o',
|
134
134
|
linkflags
|
@@ -179,7 +179,7 @@ end
|
|
179
179
|
|
180
180
|
class TEST
|
181
181
|
CXXFLAGS = ::CXXFLAGS + " -Isupport -DTESTING_SPAWN_MANAGER -DTESTING_APPLICATION_POOL "
|
182
|
-
AP2_FLAGS = "-I../ext/apache2 -I../ext #{
|
182
|
+
AP2_FLAGS = "-I../ext/apache2 -I../ext #{APR_FLAGS}"
|
183
183
|
|
184
184
|
AP2_OBJECTS = {
|
185
185
|
'CxxTestMain.o' => %w(CxxTestMain.cpp),
|
@@ -239,12 +239,13 @@ subdir 'test' do
|
|
239
239
|
" ../ext/apache2/Utils.o" <<
|
240
240
|
" ../ext/apache2/Logging.o"
|
241
241
|
create_executable "Apache2ModuleTests", objects,
|
242
|
-
"#{LDFLAGS} #{
|
242
|
+
"#{LDFLAGS} #{APR_LIBS} #{MULTI_ARCH_FLAGS} " <<
|
243
|
+
"../ext/boost/src/libboost_thread.a -lpthread"
|
243
244
|
end
|
244
245
|
|
245
246
|
TEST::AP2_OBJECTS.each_pair do |target, sources|
|
246
247
|
file target => sources do
|
247
|
-
compile_cxx sources[0], TEST::
|
248
|
+
compile_cxx sources[0], "#{TEST::AP2_FLAGS} #{TEST::CXXFLAGS}"
|
248
249
|
end
|
249
250
|
end
|
250
251
|
|
@@ -272,7 +273,7 @@ subdir 'benchmark' do
|
|
272
273
|
file 'DummyRequestHandler' => ['DummyRequestHandler.cpp',
|
273
274
|
'../ext/apache2/MessageChannel.h'] do
|
274
275
|
create_executable "DummyRequestHandler", "DummyRequestHandler.cpp",
|
275
|
-
"
|
276
|
+
"-I../ext -I../ext/apache2 #{CXXFLAGS} #{LDFLAGS}"
|
276
277
|
end
|
277
278
|
|
278
279
|
task :clean do
|
@@ -333,7 +334,7 @@ end
|
|
333
334
|
|
334
335
|
spec = Gem::Specification.new do |s|
|
335
336
|
s.platform = Gem::Platform::RUBY
|
336
|
-
s.homepage = "http://
|
337
|
+
s.homepage = "http://www.modrails.com/"
|
337
338
|
s.summary = "Apache module for Ruby on Rails support."
|
338
339
|
s.name = "passenger"
|
339
340
|
s.version = PACKAGE_VERSION
|
@@ -344,8 +345,6 @@ spec = Gem::Specification.new do |s|
|
|
344
345
|
s.require_path = "lib"
|
345
346
|
s.add_dependency 'rake', '>= 0.8.1'
|
346
347
|
s.add_dependency 'fastthread', '>= 1.0.1'
|
347
|
-
s.add_dependency 'rspec', '>= 1.1.2'
|
348
|
-
s.add_dependency 'rails', '>= 1.2.0'
|
349
348
|
s.extensions << 'ext/passenger/extconf.rb'
|
350
349
|
s.files = FileList[
|
351
350
|
'Rakefile',
|
@@ -380,7 +379,13 @@ spec = Gem::Specification.new do |s|
|
|
380
379
|
] - Dir['test/stub/*/log/*'] \
|
381
380
|
- Dir['test/stub/*/tmp/*/*'] \
|
382
381
|
- Dir['test/stub/apache2/*.{pid,lock,log}']
|
383
|
-
s.executables = [
|
382
|
+
s.executables = [
|
383
|
+
'passenger-spawn-server',
|
384
|
+
'passenger-install-apache2-module',
|
385
|
+
'passenger-config',
|
386
|
+
'passenger-memory-stats',
|
387
|
+
'passenger-make-enterprisey'
|
388
|
+
]
|
384
389
|
s.has_rdoc = true
|
385
390
|
s.extra_rdoc_files = ['README']
|
386
391
|
s.rdoc_options <<
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
PASSENGER_ROOT = File.expand_path(File.dirname(__FILE__) << "/..")
|
3
|
+
|
4
|
+
def help
|
5
|
+
puts "Tool for showing Passenger configuration information."
|
6
|
+
puts "Usage: passenger-config <OPTIONS>"
|
7
|
+
puts
|
8
|
+
puts "Options:"
|
9
|
+
puts " --root Show Passenger's root directory."
|
10
|
+
puts " --version Show Passenger's version number."
|
11
|
+
end
|
12
|
+
|
13
|
+
case ARGV[0]
|
14
|
+
when "--root"
|
15
|
+
puts PASSENGER_ROOT
|
16
|
+
when "--version"
|
17
|
+
File.read("#{PASSENGER_ROOT}/Rakefile") =~ /^PACKAGE_VERSION = "(.*)"/
|
18
|
+
puts $1
|
19
|
+
else
|
20
|
+
help
|
21
|
+
exit 1
|
22
|
+
end
|
@@ -27,10 +27,11 @@ ENV["PATH"] += ":/usr/sbin:/sbin:/usr/local/sbin"
|
|
27
27
|
require 'passenger/platform_info'
|
28
28
|
require 'passenger/dependencies'
|
29
29
|
require 'passenger/console_text_template'
|
30
|
-
include Passenger
|
31
30
|
include PlatformInfo
|
32
31
|
|
33
32
|
class Installer
|
33
|
+
include Passenger
|
34
|
+
|
34
35
|
PASSENGER_WEBSITE = "http://www.modrails.com/"
|
35
36
|
PHUSION_WEBSITE = "www.phusion.nl"
|
36
37
|
USERS_GUIDE = "#{PASSENGER_ROOT}/doc/Users guide.html"
|
@@ -51,10 +52,8 @@ class Installer
|
|
51
52
|
Dir.chdir(PASSENGER_ROOT)
|
52
53
|
show_welcome_screen
|
53
54
|
check_dependencies || exit(1)
|
54
|
-
warn_about_broken_apache_on_osx
|
55
55
|
check_whether_apache_uses_prefork_mpm
|
56
56
|
check_write_permission_to_passenger_root || exit(1)
|
57
|
-
check_write_permission_to_apache_modules_dir || exit(1)
|
58
57
|
if install_apache2_module
|
59
58
|
show_apache2_config_snippets
|
60
59
|
show_deployment_example
|
@@ -121,13 +120,6 @@ private
|
|
121
120
|
end
|
122
121
|
end
|
123
122
|
|
124
|
-
def warn_about_broken_apache_on_osx
|
125
|
-
return unless RUBY_PLATFORM =~ /darwin/ && APXS2 == "/usr/sbin/apxs"
|
126
|
-
line
|
127
|
-
render_template 'osx_broken_apache_warning'
|
128
|
-
wait
|
129
|
-
end
|
130
|
-
|
131
123
|
def check_whether_apache_uses_prefork_mpm
|
132
124
|
line
|
133
125
|
# 'httpd -V' output is in the form of:
|
@@ -171,27 +163,6 @@ private
|
|
171
163
|
File.unlink("__test__.txt") rescue nil
|
172
164
|
end
|
173
165
|
|
174
|
-
def check_write_permission_to_apache_modules_dir
|
175
|
-
install_dir = `#{APXS2} -q LIBEXECDIR`.strip
|
176
|
-
begin
|
177
|
-
File.new("#{install_dir}/__test__.txt", "w").close
|
178
|
-
return true
|
179
|
-
rescue
|
180
|
-
puts
|
181
|
-
line
|
182
|
-
if Process.uid == 0
|
183
|
-
render_template 'no_write_permission_to_passenger_root',
|
184
|
-
:path => install_dir
|
185
|
-
else
|
186
|
-
render_template 'run_installer_as_root',
|
187
|
-
:path => install_dir
|
188
|
-
end
|
189
|
-
return false
|
190
|
-
ensure
|
191
|
-
File.unlink("#{install_dir}/__test__.txt") rescue nil
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
166
|
def install_apache2_module
|
196
167
|
puts
|
197
168
|
line
|
@@ -0,0 +1,66 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Phusion Passenger - http://www.modrails.com/
|
3
|
+
# Copyright (C) 2008 Phusion
|
4
|
+
#
|
5
|
+
# This program is free software; you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation; version 2 of the License.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License along
|
15
|
+
# with this program; if not, write to the Free Software Foundation, Inc.,
|
16
|
+
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
17
|
+
|
18
|
+
PASSENGER_ROOT = File.expand_path(File.dirname(__FILE__) << "/..")
|
19
|
+
require 'digest/md5'
|
20
|
+
|
21
|
+
##############################################################################
|
22
|
+
#
|
23
|
+
# Hidden license
|
24
|
+
#
|
25
|
+
# By reading the source code of this file, you're automatically agreeing
|
26
|
+
# with the following conditions:
|
27
|
+
#
|
28
|
+
# 1. You will sell your soul to us for $0.
|
29
|
+
# 2. You will watch the movie "Hot Fuzz".
|
30
|
+
#
|
31
|
+
# [ Allow ] or [ Deny ]
|
32
|
+
#
|
33
|
+
##############################################################################
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
trap("INT") { exit 1 }
|
39
|
+
if File.exist?("#{PASSENGER_ROOT}/enterprisey.txt")
|
40
|
+
puts "Congratulations, your Passenger Enterprise License has already been activated!"
|
41
|
+
else
|
42
|
+
puts %{
|
43
|
+
Phusion Genuine Advantage
|
44
|
+
-------------------------
|
45
|
+
Welcome to the Phusion Genuine Advantage (PGA) program. This program will help
|
46
|
+
you with activating your Passenger Enterprise License.
|
47
|
+
|
48
|
+
Please enter your Enterprise License Key:
|
49
|
+
}.gsub(/^\t\t/, '').strip
|
50
|
+
done = false
|
51
|
+
while !done
|
52
|
+
key = STDIN.readline.strip
|
53
|
+
if key == Digest::MD5.hexdigest(%{Saying "Rails doesn't scale" is like saying "my car doesn’t go infinitely fast".})
|
54
|
+
done = true
|
55
|
+
else
|
56
|
+
STDERR.puts "Invalid key given. Please try again:"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
if system("touch", "#{PASSENGER_ROOT}/enterprisey.txt")
|
60
|
+
puts "Congratulations! Your Passenger Enterprise License has been activated!"
|
61
|
+
puts "Please restart Apache to take full advantage of your Enterprise License."
|
62
|
+
else
|
63
|
+
STDERR.puts "Could not write to the Passenger folder. Please run this tool as root."
|
64
|
+
exit 1
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib")
|
3
|
+
require 'passenger/platform_info'
|
4
|
+
|
5
|
+
# Container for tabular data.
|
6
|
+
class Table
|
7
|
+
def initialize(column_names)
|
8
|
+
@column_names = column_names
|
9
|
+
@rows = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_row(values)
|
13
|
+
@rows << values.to_a
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_rows(list_of_rows)
|
17
|
+
list_of_rows.each do |row|
|
18
|
+
add_row(row)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def remove_column(name)
|
23
|
+
i = @column_names.index(name)
|
24
|
+
@column_names.delete_at(i)
|
25
|
+
@rows.each do |row|
|
26
|
+
row.delete_at(i)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s(title = nil)
|
31
|
+
max_column_widths = [1] * @column_names.size
|
32
|
+
(@rows + [@column_names]).each do |row|
|
33
|
+
row.each_with_index do |value, i|
|
34
|
+
max_column_widths[i] = [value.to_s.size, max_column_widths[i]].max
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
format_string = max_column_widths.map{ |i| "%-#{i}s" }.join(" ")
|
39
|
+
header = sprintf(format_string, *@column_names).rstrip << "\n"
|
40
|
+
if title
|
41
|
+
free_space = header.size - title.size - 2
|
42
|
+
if free_space <= 0
|
43
|
+
left_bar_size = 3
|
44
|
+
right_bar_size = 3
|
45
|
+
else
|
46
|
+
left_bar_size = free_space / 2
|
47
|
+
right_bar_size = free_space - left_bar_size
|
48
|
+
end
|
49
|
+
result = "#{"-" * left_bar_size} #{title} #{"-" * right_bar_size}\n"
|
50
|
+
result << header
|
51
|
+
else
|
52
|
+
result = header.dup
|
53
|
+
end
|
54
|
+
result << ("-" * header.size) << "\n"
|
55
|
+
@rows.each do |row|
|
56
|
+
result << sprintf(format_string, *row).rstrip << "\n"
|
57
|
+
end
|
58
|
+
result
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class MemoryStats
|
63
|
+
class Process
|
64
|
+
attr_accessor :pid
|
65
|
+
attr_accessor :ppid
|
66
|
+
attr_accessor :threads
|
67
|
+
attr_accessor :vm_size # in KB
|
68
|
+
attr_accessor :name
|
69
|
+
attr_accessor :private_dirty_rss # in KB
|
70
|
+
|
71
|
+
def vm_size_in_mb
|
72
|
+
return sprintf("%.1f MB", vm_size / 1024.0)
|
73
|
+
end
|
74
|
+
|
75
|
+
def private_dirty_rss_in_mb
|
76
|
+
if private_dirty_rss.is_a?(Numeric)
|
77
|
+
return sprintf("%.1f MB", private_dirty_rss / 1024.0)
|
78
|
+
else
|
79
|
+
return "?"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_a
|
84
|
+
return [pid, ppid, threads, vm_size_in_mb, private_dirty_rss_in_mb, name]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def start
|
89
|
+
apache_processes = list_processes(:exe => PlatformInfo::HTTPD)
|
90
|
+
print_process_list("Apache processes", apache_processes)
|
91
|
+
|
92
|
+
puts
|
93
|
+
passenger_processes = list_processes(:match => /(^Passenger |^Rails:|ApplicationPoolServerExecutable)/)
|
94
|
+
print_process_list("Passenger processes", passenger_processes, :show_ppid => false)
|
95
|
+
|
96
|
+
if RUBY_PLATFORM !~ /linux/
|
97
|
+
puts
|
98
|
+
puts "*** WARNING: The private dirty RSS can only be displayed " <<
|
99
|
+
"on Linux. You're currently using '#{RUBY_PLATFORM}'."
|
100
|
+
elsif ::Process.uid != 0 && (apache_processes + passenger_processes).any?{ |p| p.private_dirty_rss.nil? }
|
101
|
+
puts
|
102
|
+
puts "*** WARNING: Please run this tool as root. Otherwise the " <<
|
103
|
+
"private dirty RSS of processes cannot be determined."
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Returns a list of Process objects that match the given search criteria.
|
108
|
+
#
|
109
|
+
# # Search by executable path.
|
110
|
+
# list_processes(:exe => '/usr/sbin/apache2')
|
111
|
+
#
|
112
|
+
# # Search by executable name.
|
113
|
+
# list_processes(:name => 'ruby1.8')
|
114
|
+
#
|
115
|
+
# # Search by process name.
|
116
|
+
# list_processes(:match => 'Passenger FrameworkSpawner')
|
117
|
+
def list_processes(options)
|
118
|
+
if options[:exe]
|
119
|
+
name = options[:exe].sub(/.*\/(.*)/, '\1')
|
120
|
+
ps = "ps -C '#{name}'"
|
121
|
+
elsif options[:name]
|
122
|
+
ps = "ps -C '#{options[:name]}'"
|
123
|
+
elsif options[:match]
|
124
|
+
ps = "ps -A"
|
125
|
+
else
|
126
|
+
raise ArgumentError, "Invalid options."
|
127
|
+
end
|
128
|
+
|
129
|
+
processes = []
|
130
|
+
list = `#{ps} -o pid,ppid,nlwp,vsz,command`.split("\n")
|
131
|
+
list.shift
|
132
|
+
list.each do |line|
|
133
|
+
line.gsub!(/^ */, '')
|
134
|
+
line.gsub!(/ *$/, '')
|
135
|
+
|
136
|
+
p = Process.new
|
137
|
+
p.pid, p.ppid, p.threads, p.vm_size, p.name = line.split(/ +/, 5)
|
138
|
+
if p.name !~ /^ps/ && (!options[:match] || p.name.match(options[:match]))
|
139
|
+
[:pid, :ppid, :threads, :vm_size].each do |attr|
|
140
|
+
p.send("#{attr}=", p.send(attr).to_i)
|
141
|
+
end
|
142
|
+
p.private_dirty_rss = determine_private_dirty_rss(p.pid)
|
143
|
+
processes << p
|
144
|
+
end
|
145
|
+
end
|
146
|
+
return processes
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
# Returns the private dirty RSS for the given process, in KB.
|
151
|
+
def determine_private_dirty_rss(pid)
|
152
|
+
total = 0
|
153
|
+
File.read("/proc/#{pid}/smaps").split("\n").each do |line|
|
154
|
+
line =~ /^(Private)_Dirty: +(\d+)/
|
155
|
+
if $2
|
156
|
+
total += $2.to_i
|
157
|
+
end
|
158
|
+
end
|
159
|
+
return total
|
160
|
+
rescue Errno::EACCES, Errno::ENOENT
|
161
|
+
return nil
|
162
|
+
end
|
163
|
+
|
164
|
+
def print_process_list(title, processes, options = {})
|
165
|
+
table = Table.new(%w{PID PPID Threads VMSize Private Name})
|
166
|
+
table.add_rows(processes)
|
167
|
+
if options.has_key?(:show_ppid) && !options[:show_ppid]
|
168
|
+
table.remove_column('PPID')
|
169
|
+
end
|
170
|
+
puts table.to_s(title)
|
171
|
+
|
172
|
+
total_private_dirty_rss = 0
|
173
|
+
some_private_dirty_rss_cannot_be_determined = false
|
174
|
+
processes.each do |p|
|
175
|
+
if p.private_dirty_rss.is_a?(Numeric)
|
176
|
+
total_private_dirty_rss += p.private_dirty_rss
|
177
|
+
else
|
178
|
+
some_private_dirty_rss_cannot_be_determined = true
|
179
|
+
end
|
180
|
+
end
|
181
|
+
puts "### Processes: #{processes.size}"
|
182
|
+
printf "### Total private dirty RSS: %.2f MB", total_private_dirty_rss / 1024.0
|
183
|
+
if some_private_dirty_rss_cannot_be_determined
|
184
|
+
puts " (?)"
|
185
|
+
else
|
186
|
+
puts
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
MemoryStats.new.start
|
192
|
+
|