From f5e9c5323f7733dd3ad62c6e88cdbe987142cf7a Mon Sep 17 00:00:00 2001 From: Masahiro Nakagawa Date: Thu, 26 Jun 2014 17:08:44 +0900 Subject: [PATCH 1/6] Remove obsoleted TcpInput StreamInput based TcpInput is obsoleted since 2+ years ago. So we can remove this class for newer plugin --- lib/fluent/plugin/in_stream.rb | 28 ---------------------------- test/plugin/test_in_stream.rb | 24 ------------------------ 2 files changed, 52 deletions(-) diff --git a/lib/fluent/plugin/in_stream.rb b/lib/fluent/plugin/in_stream.rb index d741eebf05..63d21375da 100644 --- a/lib/fluent/plugin/in_stream.rb +++ b/lib/fluent/plugin/in_stream.rb @@ -160,34 +160,6 @@ def on_close end end - - # obsolete - # ForwardInput is backward compatible with TcpInput - #class TcpInput < StreamInput - # Plugin.register_input('tcp', self) - # - # config_param :port, :integer, :default => DEFAULT_LISTEN_PORT - # config_param :bind, :string, :default => '0.0.0.0' - # - # def configure(conf) - # super - # end - # - # def listen - # log.debug "listening fluent socket on #{@bind}:#{@port}" - # Coolio::TCPServer.new(@bind, @port, Handler, method(:on_message)) - # end - #end - class TcpInput < ForwardInput - Plugin.register_input('tcp', self) - - def initialize - super - $log.warn "'tcp' input is obsoleted and will be removed soon. Use 'forward' instead." - end - end - - class UnixInput < StreamInput Plugin.register_input('unix', self) diff --git a/test/plugin/test_in_stream.rb b/test/plugin/test_in_stream.rb index b30356bbe2..ce1bba0464 100644 --- a/test/plugin/test_in_stream.rb +++ b/test/plugin/test_in_stream.rb @@ -105,30 +105,6 @@ def send_data(data) end end -class TcpInputTest < Test::Unit::TestCase - include StreamInputTest - - PORT = unused_port - CONFIG = %[ - port #{PORT} - bind 127.0.0.1 - ] - - def create_driver(conf=CONFIG) - super(Fluent::TcpInput, conf) - end - - def test_configure - d = create_driver - assert_equal PORT, d.instance.port - assert_equal '127.0.0.1', d.instance.bind - end - - def connect - TCPSocket.new('127.0.0.1', PORT) - end -end - class UnixInputTest < Test::Unit::TestCase include StreamInputTest From ae8d900d35e420fa25e6bd0c1ee6052980be9cb2 Mon Sep 17 00:00:00 2001 From: Masahiro Nakagawa Date: Thu, 26 Jun 2014 18:38:12 +0900 Subject: [PATCH 2/6] Add udp input plugin --- lib/fluent/plugin/in_udp.rb | 17 +++++ lib/fluent/plugin/socket_util.rb | 116 +++++++++++++++++++++++++++++++ test/plugin/test_in_udp.rb | 97 ++++++++++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 lib/fluent/plugin/in_udp.rb create mode 100755 test/plugin/test_in_udp.rb diff --git a/lib/fluent/plugin/in_udp.rb b/lib/fluent/plugin/in_udp.rb new file mode 100644 index 0000000000..31228ac4b4 --- /dev/null +++ b/lib/fluent/plugin/in_udp.rb @@ -0,0 +1,17 @@ +require 'fluent/plugin/socket_util' + +module Fluent + class UdpInput < SocketUtil::BaseInput + Plugin.register_input('udp', self) + + config_set_default :port, 5160 + config_param :body_size_limit, :size, :default => 4096 + + def listen(callback) + log.debug "listening udp socket on #{@bind}:#{@port}" + @usock = SocketUtil.create_udp_socket(@bind) + @usock.bind(@bind, @port) + SocketUtil::UdpHandler.new(@usock, log, @body_size_limit, callback) + end + end +end diff --git a/lib/fluent/plugin/socket_util.rb b/lib/fluent/plugin/socket_util.rb index 9c689b6805..2667f3b95e 100644 --- a/lib/fluent/plugin/socket_util.rb +++ b/lib/fluent/plugin/socket_util.rb @@ -1,3 +1,5 @@ +require 'cool.io' + module Fluent module SocketUtil def create_udp_socket(host) @@ -10,5 +12,119 @@ def create_udp_socket(host) end end module_function :create_udp_socket + + class UdpHandler < Coolio::IO + def initialize(io, log, body_size_limit, callback) + super(io) + @io = io + @log = log + @body_size_limit = body_size_limit + @callback = callback + end + + def on_readable + msg, addr = @io.recvfrom_nonblock(@body_size_limit) + @callback.call(msg, addr) + rescue => e + @log.error "unexpected error", :error => e, :error_class => e.class + end + end + + class TcpHandler < Coolio::Socket + def initialize(io, log, delimiter, callback) + super(io) + if io.is_a?(TCPSocket) + @addr = (io.peeraddr rescue PEERADDR_FAILED) + + opt = [1, @timeout.to_i].pack('I!I!') # { int l_onoff; int l_linger; } + io.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, opt) + end + @delimiter = delimiter + @callback = callback + @log = log + @log.trace { "accepted fluent socket object_id=#{self.object_id}" } + @buffer = "".force_encoding('ASCII-8BIT') + end + + def on_connect + end + + def on_read(data) + @buffer << data + pos = 0 + + while i = @buffer.index(@delimiter, pos) + msg = @buffer[pos..i] + @callback.call(msg, @addr) + pos = i + 1 + end + @buffer.slice!(0, pos) if pos > 0 + rescue => e + @log.error "unexpected error", :error => e, :error_class => e.class + close + end + + def on_close + @log.trace { "closed fluent socket object_id=#{self.object_id}" } + end + end + + class BaseInput < Fluent::Input + def initialize + super + require 'fluent/parser' + end + + config_param :tag, :string + config_param :format, :string + config_param :port, :integer, :default => 5150 + config_param :bind, :string, :default => '0.0.0.0' + config_param :source_host_key, :string, :default => nil + + def configure(conf) + super + + @parser = TextParser.new + @parser.configure(conf) + end + + def start + @loop = Coolio::Loop.new + @handler = listen(method(:on_message)) + @loop.attach(@handler) + @thread = Thread.new(&method(:run)) + end + + def shutdown + @loop.watchers.each { |w| w.detach } + @loop.stop + @handler.close + @thread.join + end + + def run + @loop.run + rescue => e + log.error "unexpected error", :error => e, :error_class => e.class + log.error_backtrace + end + + private + + def on_message(msg, addr) + @parser.parse(msg) { |time, record| + unless time && record + log.warn "pattern not match: #{msg.inspect}" + return + end + + record[@source_host_key] = addr[3] if @source_host_key + Engine.emit(@tag, time, record) + } + rescue => e + log.error msg.dump, :error => e, :error_class => e.class, :host => addr[3] + log.error_backtrace + end + end end end diff --git a/test/plugin/test_in_udp.rb b/test/plugin/test_in_udp.rb new file mode 100755 index 0000000000..df91597e54 --- /dev/null +++ b/test/plugin/test_in_udp.rb @@ -0,0 +1,97 @@ +require 'fluent/test' +require 'helper' + +class UdpInputTest < Test::Unit::TestCase + def setup + Fluent::Test.setup + end + + PORT = unused_port + CONFIG = %! + port #{PORT} + bind 127.0.0.1 + tag udp + format /^\\[(?