#!/usr/bin/env ruby

require 'rubygems'
require 'bundler'

require 'optparse'
require 'yaml'
require 'pathname'
require 'socket'

require 'daemons'
require 'eventmachine'
require 'eventmachine-tail'

require 'remote_syslog'

def remote_syslog_daemon(args)
  options = {
    :configfile => '/etc/log_files.yml',
    :dest_host => 'logs.papertrailapp.com',
    :dest_port => 514
  }
  daemonize_options = {
     :app_name   => File.basename($0) || "remote_syslog",
     :ARGV       => ['start'],
     :dir_mode   => :system,
     :multiple   => false,
     :ontop      => false,
     :mode       => :exec,
     :backtrace  => false,
     :monitor    => false
  }

  op = OptionParser.new do |opts|
    opts.banner = "Usage:   remote_syslog [options] <path to add'l log 1> .. <path to add'l log n>"
    opts.separator ''
    opts.separator "Example: remote_syslog -c configs/logs.yml -p 12345 /var/log/mysqld.log"
    opts.separator ''
    opts.separator "Options:"
    
    opts.on("-c", "--configfile PATH", "Path to config (/etc/log_files.yml)") do |v|
      options[:configfile] = File.expand_path(v)
    end
    opts.on("-d", "--dest-host HOSTNAME", "Destination syslog hostname or IP (logs.papertrailapp.com)") do |v|
      options[:dest_host] = v
    end
    opts.on("-D", "--no-detach", "Don't daemonize and detach from the terminal") do
      daemonize_options[:ontop] = true
      daemonize_options[:ARGV]  = ['run']
      # write PID file in . because /var/run is sometimes only writable by root
      daemonize_options[:dir_mode] = :script
      daemonize_options[:dir] = '.'
    end
    opts.on("-f", "--facility FACILITY", "Facility (user)") do |v|
      options[:facility] = v.upcase
    end
    opts.on("-p", "--dest-port PORT", "Destination syslog port (514)") do |v|
      options[:dest_port] = v
    end
    opts.on("-P", "--pid-dir DIRECTORY", "Directory to write .pid file in (/var/run/)") do |v|
      daemonize_options[:dir_mode] = :script
      daemonize_options[:dir] = v
    end
    opts.on("-s", "--severity SEVERITY", "Severity (notice)") do |v|
      options[:severity] = v.upcase
    end
    opts.on_tail("-h", "--help", "Show this message") do
      puts opts
      exit
    end
  end
  
  op.parse!
  
  files = ARGV
  if File.exist?(options[:configfile])
    config = open(options[:configfile]) do |f|
      YAML.load(f)
    end
    
    files += config['files']
    if config['destination']
      options[:dest_host] = config['destination']['host'] if config['destination']['host']
      options[:dest_port] = config['destination']['port'] if config['destination']['port']
    end
  elsif files.empty?
    puts "No filenames provided and #{options[:configfile]} not found."
    puts ''
    puts op
    exit
  end

  # handle relative paths before Daemonize changes the wd to /
  files.map! { |f| File.expand_path(f) }

  Daemons.run_proc(daemonize_options[:app_name], daemonize_options) do
    EventMachine.run do
      socket = EventMachine.open_datagram_socket('0.0.0.0', 0)
      
      files.each do |path|
        begin
          EventMachine::file_tail(File.expand_path(path), RemoteSyslog::Reader, 
                                  options[:dest_host], options[:dest_port],
                                  { :socket => socket, :facility => options[:facility], 
                                    :severity => options[:severity] })
                                  
        rescue Errno::ENOENT => e
          puts "#{File.expand_path(path)} not found, continuing. (#{e.message})"
        end
      end
    end
  end
  
end

remote_syslog_daemon(ARGV)