Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
tag: release-4.0.13
Fetching contributors…

Cannot retrieve contributors at this time

executable file 267 lines (237 sloc) 7.977 kb
#!/usr/bin/env ruby
# Phusion Passenger - https://www.phusionpassenger.com/
# Copyright (c) 2010-2013 Phusion
#
# "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
source_root = File.expand_path("..", File.dirname(__FILE__))
$LOAD_PATH.unshift("#{source_root}/lib")
require 'phusion_passenger'
PhusionPassenger.locate_directories
require 'phusion_passenger/platform_info'
require 'phusion_passenger/admin_tools/server_instance'
require 'phusion_passenger/utils/ansi_colors'
require 'optparse'
include PhusionPassenger::AdminTools
include PhusionPassenger::Utils::AnsiColors
DEFAULT_OPTIONS = { :show => 'pool' }.freeze
##### Show status command #####
def command_show_status(argv, options)
if argv.empty?
server_instance = find_sole_server_instance
else
server_instance = find_server_instance_on_pid(argv[0].to_i)
end
show_status(server_instance, options)
end
def find_sole_server_instance
server_instances = ServerInstance.list
if server_instances.empty?
abort "ERROR: Phusion Passenger doesn't seem to be running."
elsif server_instances.size == 1
return server_instances.first
else
puts "It appears that multiple Passenger instances are running. Please select a"
puts "specific one by running:"
puts
puts " passenger-status <PID>"
puts
puts "The following Passenger instances are running:"
server_instances.each do |instance|
puts " PID: #{instance.pid}"
end
exit 1
end
end
def find_server_instance_on_pid(pid)
if server_instance = ServerInstance.for_pid(pid)
return server_instance
else
abort "ERROR: there doesn't seem to be a Phusion Passenger instance running on PID #{pid}."
end
end
def show_status(server_instance, options)
puts "Version : #{PhusionPassenger::VERSION_STRING}"
puts "Date : #{Time.now}"
puts "Instance: #{server_instance.pid}"
case options[:show]
when 'pool'
client = server_instance.connect(:role => :passenger_status)
begin
puts client.pool_status(:verbose => options[:verbose], :colorize => true)
rescue SystemCallError => e
STDERR.puts "*** ERROR: Cannot query status for Phusion Passenger instance #{server_instance.pid}:"
STDERR.puts e.to_s
exit 2
end
when 'requests'
client = server_instance.connect(:role => :passenger_status)
begin
puts client.helper_agent_requests
rescue SystemCallError => e
STDERR.puts "*** ERROR: Cannot query status for Phusion Passenger instance #{server_instance.pid}:"
STDERR.puts e.to_s
exit 2
end
when 'backtraces'
client = server_instance.connect(:role => :passenger_status)
begin
text = client.helper_agent_backtraces
rescue SystemCallError => e
STDERR.puts "*** ERROR: Cannot query status for Phusion Passenger instance #{control_process.pid}:"
STDERR.puts e.to_s
exit 2
end
# Colorize output
text.gsub!(/^(Thread .*:)$/, BLACK_BG + YELLOW + '\1' + RESET)
text.gsub!(/^( +in '.*? )(.*?)\(/, '\1' + BOLD + '\2' + RESET + '(')
puts text
when 'xml'
client = server_instance.connect(:role => :passenger_status)
begin
xml = client.pool_xml
rescue SystemCallError => e
STDERR.puts "*** ERROR: Cannot query status for Phusion Passenger instance #{control_process.pid}:"
STDERR.puts e.to_s
exit 2
end
indented = format_with_xmllint(xml)
if indented
puts indented
else
puts xml
STDERR.puts "*** Tip: if you install the 'xmllint' command then the XML output will be indented."
end
when 'union_station'
client = server_instance.connect(:role => :passenger_status, :socket_name => 'logging_admin')
begin
response = client.logging_agent_status
rescue SystemCallError => e
STDERR.puts "*** ERROR: Cannot query status for Phusion Passenger instance #{control_process.pid}:"
STDERR.puts e.to_s
exit 2
end
puts response
end
rescue ServerInstance::RoleDeniedError
require 'phusion_passenger/platform_info/ruby'
STDERR.puts "*** ERROR: You are not authorized to query the status for this Phusion " <<
"Passenger instance. Please try again with '#{PhusionPassenger::PlatformInfo.ruby_sudo_command}'."
exit 2
rescue ServerInstance::CorruptedDirectoryError
STDERR.puts "*** ERROR: The server instance directory #{server_instance.path} is corrupted. " <<
"This could have two causes:\n" <<
"\n" <<
" 1. The Phusion Passenger instance is no longer running, but failed to cleanup the directory. " <<
"Please delete this directory and ignore the problem.\n" <<
" 2. An external program corrupted the directory. Please restart Phusion Passenger.\n"
exit 2
ensure
client.close if client
end
def format_with_xmllint(xml)
return nil if !PhusionPassenger::PlatformInfo.find_command('xmllint')
require 'open3'
require 'thread'
ENV['XMLLINT_INDENT'] = ' '
Open3.popen3("xmllint", "--format", "-") do |stdin, stdout, stderr|
stdout_text = nil
stderr_text = nil
thread1 = Thread.new do
stdin.write(xml)
stdin.close
end
thread2 = Thread.new do
stdout_text = stdout.read
stdout.close
end
thread3 = Thread.new do
stderr_text = stderr.read
stderr.close
end
thread1.join
thread2.join
thread3.join
if stdout_text.nil? || stdout_text.empty?
if stderr_text !~ /No such file or directory/ && stderr_text !~ /command not found/
STDERR.puts stderr_text
end
return nil
else
return stdout_text
end
end
end
##### Main command dispatcher #####
def create_option_parser(options)
return OptionParser.new do |opts|
opts.banner = "Usage: passenger-status [options] [Phusion Passenger's PID]"
opts.separator ""
opts.separator "Tool for inspecting Phusion Passenger's internal status."
opts.separator ""
opts.separator "Options:"
opts.on("--show=pool|requests|backtraces|xml|union_station", String,
"Whether to show the pool's contents,\n" <<
"#{' ' * 37}the currently running requests,\n" <<
"#{' ' * 37}the backtraces of all threads or an XML\n" <<
"#{' ' * 37}description of the pool.") do |what|
if what !~ /\A(pool|requests|backtraces|xml|union_station)\Z/
STDERR.puts "Invalid argument for --show."
exit 1
else
options[:show] = what
end
end
opts.on("--verbose", "-v", "Show verbose information.") do
options[:verbose] = true
end
end
end
def parse_argv
options = DEFAULT_OPTIONS.dup
parser = create_option_parser(options)
begin
parser.parse!
rescue OptionParser::ParseError => e
puts e
puts
puts "Please see '--help' for valid options."
exit 1
end
return options
end
def infer_command
if !ARGV[0] || ARGV[0] =~ /\A[0-9]+\Z/
return [:show_status, ARGV.dup]
else
command_name, *argv = ARGV
if respond_to?("command_#{command_name}")
return [command_name, argv]
else
abort "ERROR: unrecognized command '#{command_name}'"
end
end
end
def start
options = parse_argv
command, argv = infer_command
send("command_#{command}", argv, options)
end
start
Jump to Line
Something went wrong with that request. Please try again.