class Fluent::Ctl

Constants

COMMAND_MAP
DEFAULT_OPTIONS
WINSVC_CONTROL_CODE_MAP

Public Class Methods

new(argv = ARGV) click to toggle source
# File lib/fluent/command/ctl.rb, line 60
def initialize(argv = ARGV)
  @argv = argv
  @options = {}
  @opt_parser = OptionParser.new
  configure_option_parser
  @options.merge!(DEFAULT_OPTIONS)
  parse_options!
end

Public Instance Methods

call() click to toggle source
# File lib/fluent/command/ctl.rb, line 93
def call
  if Fluent.windows?
    if /^[0-9]+$/.match?(@pid_or_svcname)
      # Use as PID
      return call_windows_event(@command, "fluentd_#{@pid_or_svcname}")
    end

    unless call_winsvc_control_code(@command, @pid_or_svcname)
      puts "Cannot send control code to #{@pid_or_svcname} service, try to send an event with this name ..."
      call_windows_event(@command, @pid_or_svcname)
    end
  else
    call_signal(@command, @pid_or_svcname)
  end
end
help_text() click to toggle source
# File lib/fluent/command/ctl.rb, line 69
def help_text
  text = "\n"
  if Fluent.windows?
    text << "Usage: #{$PROGRAM_NAME} COMMAND [PID_OR_SVCNAME]\n"
  else
    text << "Usage: #{$PROGRAM_NAME} COMMAND PID\n"
  end
  text << "\n"
  text << "Commands: \n"
  COMMAND_MAP.each do |key, value|
    text << "  #{key}\n"
  end
  text
end
usage(msg = nil) click to toggle source
# File lib/fluent/command/ctl.rb, line 84
def usage(msg = nil)
  puts help_text
  if msg
    puts
    puts "Error: #{msg}"
  end
  exit 1
end

Private Instance Methods

call_signal(command, pid) click to toggle source
# File lib/fluent/command/ctl.rb, line 111
def call_signal(command, pid)
  signal = COMMAND_MAP[command.to_sym]
  Process.kill(signal, pid.to_i)
end
call_windows_event(command, pid_or_svcname) click to toggle source
# File lib/fluent/command/ctl.rb, line 143
def call_windows_event(command, pid_or_svcname)
  prefix = pid_or_svcname
  event_name = COMMAND_MAP[command.to_sym]
  suffix = event_name.empty? ? "" : "_#{event_name}"

  begin
    event = Win32::Event.open("#{prefix}#{suffix}")
    event.set
    event.close
  rescue Errno::ENOENT
    puts "Error: Cannot find the fluentd process with the event name: \"#{prefix}\""
  end
end
call_winsvc_control_code(command, pid_or_svcname) click to toggle source
# File lib/fluent/command/ctl.rb, line 116
def call_winsvc_control_code(command, pid_or_svcname)
  status = SERVICE_STATUS.new

  begin
    handle_scm = OpenSCManager(nil, nil, SC_MANAGER_CONNECT)
    FFI.raise_windows_error('OpenSCManager') if handle_scm == 0

    handle_scs = OpenService(handle_scm, "fluentdwinsvc", SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL)
    FFI.raise_windows_error('OpenService') if handle_scs == 0

    control_code = WINSVC_CONTROL_CODE_MAP[command.to_sym]

    unless ControlService(handle_scs, control_code, status)
      FFI.raise_windows_error('ControlService')
    end
  rescue => e
    puts e
    state = status[:dwCurrentState]
    return state == SERVICE_STOPPED || state == SERVICE_STOP_PENDING
  ensure
    CloseServiceHandle(handle_scs)
    CloseServiceHandle(handle_scm)
  end

  return true
end
configure_option_parser() click to toggle source
# File lib/fluent/command/ctl.rb, line 157
def configure_option_parser
  @opt_parser.banner = help_text
  @opt_parser.version = Fluent::VERSION
end
parse_options!() click to toggle source
# File lib/fluent/command/ctl.rb, line 162
def parse_options!
  @opt_parser.parse!(@argv)

  @command = @argv[0]
  @pid_or_svcname = @argv[1] || "fluentdwinsvc"

  usage("Command isn't specified!") if @command.nil? || @command.empty?
  usage("Unknown command: #{@command}") unless COMMAND_MAP.has_key?(@command.to_sym)

  if Fluent.windows?
    usage("PID or SVCNAME isn't specified!") if @pid_or_svcname.nil? || @pid_or_svcname.empty?
  else
    usage("PID isn't specified!") if @pid_or_svcname.nil? || @pid_or_svcname.empty?
    usage("Invalid PID: #{pid}") unless /^[0-9]+$/.match?(@pid_or_svcname)
  end
end