Browse files

Cache DNS resolution and allow for stripping of ASCII color codes.

  • Loading branch information...
1 parent aa1a02c commit fee58bd9b1e4ea997351f0931a73cc2f2e08b717 @eric eric committed May 25, 2011
Showing with 73 additions and 59 deletions.
  1. +3 −3 Gemfile
  2. +17 −13 bin/remote_syslog
  3. +51 −39 lib/remote_syslog/reader.rb
  4. +2 −4 remote_syslog.gemspec
View
6 Gemfile
@@ -1,3 +1,3 @@
-gem 'daemons'
-gem 'eventmachine'
-gem 'eventmachine-tail'
+source :rubygems
+
+gemspec
View
30 bin/remote_syslog
@@ -14,18 +14,19 @@ require 'remote_syslog'
def remote_syslog_daemon(args)
options = {
:configfile => '/etc/log_files.yml',
- :dest_host => 'logs.papertrailapp.com',
- :dest_port => 514
+ :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
+ :app_name => File.basename($0) || "remote_syslog",
+ :ARGV => ['start'],
+ :dir_mode => :system,
+ :multiple => false,
+ :ontop => false,
+ :mode => :exec,
+ :backtrace => false,
+ :monitor => false,
+ :strip_color => false
}
op = OptionParser.new do |opts|
@@ -61,6 +62,9 @@ def remote_syslog_daemon(args)
opts.on("-s", "--severity SEVERITY", "Severity (notice)") do |v|
options[:severity] = v.upcase
end
+ opts.on("--strip-color", "Strip color codes") do
+ options[:strip_color] = true
+ end
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit
@@ -97,9 +101,9 @@ def remote_syslog_daemon(args)
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] })
+ options[:dest_host], options[:dest_port],
+ :socket => socket, :facility => options[:facility],
+ :severity => options[:severity], :strip_color => options[:strip_color])
rescue Errno::ENOENT => e
puts "#{File.expand_path(path)} not found, continuing. (#{e.message})"
View
90 lib/remote_syslog/reader.rb
@@ -1,57 +1,69 @@
+require 'eventmachine'
+require 'eventmachine-tail'
+require 'em-dns-resolver'
+require 'syslog_protocol'
+
module RemoteSyslog
class Reader < EventMachine::FileTail
- def initialize(path, dest_addr, dest_port, options = {})
- @dest_addr = dest_addr
- @dest_port = dest_port.to_i
-
+ COLORED_REGEXP = /\e\[(?:(?:[34][0-7]|[0-9]);){0,2}(?:[34][0-7]|[0-9])m/
+
+ def initialize(path, destination_address, destination_port, options = {})
+ super(path, -1)
+
+ @destination_address = destination_address
+ @destination_port = destination_port.to_i
+
+ @strip_color = options[:strip_color]
+
@socket = options[:socket] || EventMachine.open_datagram_socket('0.0.0.0', 0)
- @program = options[:program] || File.basename(path) || 'remote_syslog'
- @hostname = options[:hostname] || `hostname`.strip
- @hostname = 'localhost' unless @hostname && @hostname != ''
-
- if options[:severity]
- @severity = severity_value(options[:severity]) || raise(ArgumentError, "Invalid severity: #{options[:severity]} (valid: #{severities.keys.join(', ')})")
- else
- @severity = severity_value(:notice)
+
+ @buffer = BufferedTokenizer.new
+
+ @packet = SyslogProtocol::Packet.new
+
+ local_hostname = options[:hostname] || (Socket.gethostname rescue `hostname`.chomp)
+ if local_hostname.nil? || local_hostname.empty?
+ local_hostname = 'localhost'
end
-
- if options[:facility]
- @facility = facility_value(options[:facility]) || raise(ArgumentError, "Invalid facility: #{options[:facility]} (valid: #{facilities.keys.join(', ')}")
- else
- @facility = facility_value(:user)
+
+ @packet.hostname = local_hostname
+ @packet.facility = options[:facility] || 'user'
+ @packet.severity = options[:severity] || 'notice'
+ @packet.tag = options[:program] || File.basename(path) || File.basename($0)
+
+ # Try to resolve the destination address
+ resolve_destination_address
+
+ # Every 60 seconds we'll see if the address has changed
+ EventMachine.add_periodic_timer(60) do
+ resolve_destination_address
end
+ end
- super(path, -1)
- @buffer = BufferedTokenizer.new
+ def resolve_destination_address
+ request = EventMachine::DnsResolver.resolve(@destination_address)
+ request.callback do |addrs|
+ @cached_destination_ip = addrs.first
+ end
end
-
+
def receive_data(data)
@buffer.extract(data).each do |line|
transmit(line)
end
end
+ def destination_address
+ @cached_destination_ip || @destination_address
+ end
+
def transmit(message)
- time ||= Time.now
- day = time.strftime('%b %d').sub(/0(\d)/, ' \\1')
+ message = message.gsub(COLORED_REGEXP, '') if @strip_color
- @socket.send_datagram("<#{(@facility) + @severity}>#{day} #{time.strftime('%T')} #{@hostname} #{@program}: #{message}", @dest_addr, @dest_port)
- end
-
- def facility_value(f)
- f.is_a?(Integer) ? f*8 : facilities[f.to_sym]
- end
-
- def severity_value(s)
- s.is_a?(Integer) ? s : severities[s.to_sym]
- end
-
- def facilities
- Levels::FACILITIES
- end
-
- def severities
- Levels::SEVERITIES
+ packet = @packet.dup
+ packet.content = message
+
+ @socket.send_datagram(packet.assemble, destination_address, @destination_port)
end
end
end
View
6 remote_syslog.gemspec
@@ -28,10 +28,6 @@ Gem::Specification.new do |s|
## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
s.require_paths = %w[lib]
- ## This sections is only necessary if you have C extensions.
- #s.require_paths << 'ext'
- #s.extensions = %w[ext/extconf.rb]
-
## If your gem includes any executables, list them here.
s.executables = ['remote_syslog']
s.default_executable = 'remote_syslog'
@@ -47,6 +43,8 @@ Gem::Specification.new do |s|
s.add_dependency 'daemons'
s.add_dependency 'eventmachine'
s.add_dependency 'eventmachine-tail'
+ s.add_dependency 'syslog_protocol'
+ s.add_dependency 'em-resolv-replace'
## List your development dependencies here. Development dependencies are
## those that are only needed during development

0 comments on commit fee58bd

Please sign in to comment.