????

Your IP : 3.15.214.244


Current Path : /opt/cpanel/ea-ruby27/root/usr/sbin/
Upload File :
Current File : //opt/cpanel/ea-ruby27/root/usr/sbin/passenger-memory-stats

#!/opt/cpanel/ea-ruby27/root/usr/bin/ruby
#  Phusion Passenger - https://www.phusionpassenger.com/
#  Copyright (c) 2010-2017 Phusion Holding B.V.
#
#  "Passenger", "Phusion Passenger" and "Union Station" are registered
#  trademarks of Phusion Holding B.V.
#
#  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.


ENV["PASSENGER_LOCATION_CONFIGURATION_FILE"] = "/opt/cpanel/ea-ruby27/root/usr/share/passenger/phusion_passenger/locations.ini"
begin
  require 'rubygems'
rescue LoadError
end
require '/opt/cpanel/ea-ruby27/root/usr/share/passenger/phusion_passenger'


PhusionPassenger.locate_directories
PhusionPassenger.require_passenger_lib 'platform_info'
PhusionPassenger.require_passenger_lib 'platform_info/ruby'
PhusionPassenger.require_passenger_lib 'admin_tools/memory_stats'
PhusionPassenger.require_passenger_lib 'utils/ansi_colors'
require 'optparse'

include PhusionPassenger

# Container for tabular data.
class Table
  def initialize(column_names, colors)
    @column_names = column_names
    @rows = []
    @colors = colors
  end

  def add_row(values)
    @rows << values.to_a
  end

  def add_rows(list_of_rows)
    list_of_rows.each do |row|
      add_row(row)
    end
  end

  def remove_column(name)
    i = @column_names.index(name)
    @column_names.delete_at(i)
    @rows.each do |row|
      row.delete_at(i)
    end
  end

  def to_s(title = nil)
    max_column_widths = [1] * @column_names.size
    (@rows + [@column_names]).each do |row|
      row.each_with_index do |value, i|
        max_column_widths[i] = [value.to_s.size, max_column_widths[i]].max
      end
    end

    format_string = max_column_widths.map{ |i| "%#{-i}s" }.join("  ")
    header = sprintf(format_string, *@column_names).rstrip << "\n"
    if title
      free_space = header.size - title.size - 2
      if free_space <= 0
        left_bar_size = 3
        right_bar_size = 3
      else
        left_bar_size = free_space / 2
        right_bar_size = free_space - left_bar_size
      end
      result = "#{@colors.blue_bg}#{@colors.bold}#{@colors.yellow}\n"
      result << "#{"-" * left_bar_size} #{title} #{"-" * right_bar_size}\n"
      if !@rows.empty?
        result << @colors.white
        result << header
      end
    else
      result = header.dup
    end
    if @rows.empty?
      result << @colors.reset
    else
      result << ("-" * header.size) << "#{@colors.reset}\n"
      @rows.each do |row|
        result << sprintf(format_string, *row).rstrip << "\n"
      end
    end
    result
  end
end

# Parses the specific commandline options.
#
# Modeled after `passenger-status` logic, with minor tweaks.
#
class CommandLineOptionsParser
  def parse
    options = {}
    parser = create_option_parser(options)

    begin
      parser.parse!
      options
    rescue OptionParser::ParseError => e
      STDERR.puts e
      STDERR.puts
      STDERR.puts "Please see '--help' for valid options."

      exit 1
    end
  end

  private

  def create_option_parser(options)
    OptionParser.new do |opts|
      opts.banner = "Usage: #{File.basename(__FILE__)} [-h|--help] [--no-apache] [--no-nginx]"

      opts.separator ""
      opts.separator "Tool for inspecting the application server and Phusion Passenger's memory statistics."
      opts.separator ""

      opts.separator "Options:"

      opts.on("--no-apache", "Do not display the Apache statistics.") do
        options[:no_apache] = true
      end
      opts.on("--no-nginx", "Do not display the Nginx statistics.") do
        options[:no_nginx] = true
      end
    end
  end
end

class App
  def initialize
    @stats = AdminTools::MemoryStats.new
    @colors = Utils::AnsiColors.new
  end

  def start(options = {})
    print_apache_stats = !options.fetch(:no_apache, false)
    print_nginx_stats = !options.fetch(:no_nginx, false)

    puts "Version: #{PhusionPassenger::VERSION_STRING}"
    puts "Date   : #{Time.now}"

    if print_apache_stats
      if @stats.apache_processes
        print_process_list("Apache processes", @stats.apache_processes)
      else
        puts "#{@colors.blue_bg}#{@colors.bold}#{@colors.yellow}------------- Apache processes -------------#{@colors.reset}\n"
        STDERR.puts "*** WARNING: The Apache executable cannot be found."
        STDERR.puts "Please set the APXS2 environment variable to your 'apxs2' " <<
          "executable's filename, or set the HTTPD environment variable " <<
          "to your 'httpd' or 'apache2' executable's filename."
      end
    end

    if print_nginx_stats
      puts
      print_process_list("Nginx processes", @stats.nginx_processes)
    end

    puts
    print_process_list("Passenger processes", @stats.passenger_processes, :show_ppid => false)

    if @stats.platform_provides_private_dirty_rss_information? &&
       Process.euid != 0 &&
       @stats.root_privileges_required_for_private_dirty_rss?
      puts "*** WARNING: Please run this tool with #{@colors.bold}#{PlatformInfo.ruby_sudo_command}#{@colors.reset}. Otherwise the " <<
        "private dirty RSS (a reliable metric for real memory usage) of processes cannot be determined."
    end
  end

private
  def print_process_list(title, processes, options = {})
    table = Table.new(%w{PID PPID VMSize Private Resident Name}, @colors)
    table.add_rows(processes)
    if options.has_key?(:show_ppid) && !options[:show_ppid]
      table.remove_column('PPID')
    end
    if @stats.platform_provides_private_dirty_rss_information?
      table.remove_column('Resident')
    else
      table.remove_column('Private')
    end
    puts table.to_s(title)

    if @stats.platform_provides_private_dirty_rss_information?
      total_private_dirty_rss = 0
      some_private_dirty_rss_cannot_be_determined = false
      processes.each do |p|
        if p.private_dirty_rss.is_a?(Numeric)
          total_private_dirty_rss += p.private_dirty_rss
        else
          some_private_dirty_rss_cannot_be_determined = true
        end
      end
      puts   "### Processes: #{processes.size}"
      printf "### Total private dirty RSS: %.2f MB", total_private_dirty_rss / 1024.0
      if some_private_dirty_rss_cannot_be_determined
        puts " (?)"
      else
        puts
      end
    end
  end
end

options = CommandLineOptionsParser.new.parse
App.new.start(options)