fluent-plugin-in-udp-event 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MDNkZjg0ZmIyMGZiYzRkMzA3MzlhZjg2YjQ0ZjkwNThhMWU3YTIwMw==
5
+ data.tar.gz: !binary |-
6
+ NmJmNjNkNGZlMWRlYmQ4OTljNzBmMDUzZWM5ZDk4YWUzZWIyNDUwZA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NTQ4ODQ3OTFjNGJlYWI5ZDc2NDZlNjI1ZTgzNDAzMmZhMDViNjU2MTE0ODEy
10
+ MDUwY2QwZjdkNDg1ZmFjODViYzBjMmI4MWQzNTI3YzU4ZDUxZjNhZWY2ZTRh
11
+ Y2VmNDVlYWQ5ODcwZDEyYTE1MWI3NTU3MGY3NjZhY2VmOWU4OWY=
12
+ data.tar.gz: !binary |-
13
+ YjM2ZGY3NDEyZWM4OGM4M2ZmNTc1NjViMDE5MTU2M2Y2ZWYzNDMyYzk2NDgz
14
+ OWExMDFhOGI0ZmZmNGU4ZGY0YjZjZDBkYzkxOTZiOWU1YWYxMGFjOTVhMWI2
15
+ ZmYwOTliNDZjOWM5ZTdjZjE4ZDA4NzEzZTEwZjMwZjVlYWM5NTA=
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 ablagoev
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,31 @@
1
+ = fluent-plugin-in-udp-event {<img src="https://travis-ci.org/ablagoev/fluent-plugin-in-udp-event.png?branch=master" />}[https://travis-ci.org/ablagoev/fluent-plugin-in-udp-event]
2
+
3
+ An event driven Fluentd[http://fluentd.org/] input plugin for sending logs through UDP. The plugin uses Cool.io[http://coolio.github.io/] similarly to other parts in Fluentd.
4
+
5
+ The incoming max message size can be configured through the max_message_size config option. It is 1024 bytes by default, any messages larger than this will be ignored.
6
+
7
+ Messages should be in JSON format, following fluentd's common message structure:
8
+
9
+ [tag, timestamp, data]
10
+
11
+ == Installations:
12
+
13
+ `gem install fluent-in-udp-event`
14
+
15
+ == Usage:
16
+
17
+ # Configuration file fluent.conf
18
+ <source>
19
+ type udp_event
20
+ port 24224
21
+ bind 0.0.0.0
22
+ max_message_size 2048
23
+ </source>
24
+
25
+
26
+ The plugin was heavily influenced by the in_syslog[https://github.com/fluent/fluentd/blob/master/lib/fluent/plugin/in_syslog.rb] plugin in fluentd.
27
+
28
+ == Copyright
29
+
30
+ Copyright (c) 2013 ablagoev. See LICENSE.txt for
31
+ further details.
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.test_files = (Dir["test/*.rb"] + Dir["test/fluent/plugin/*.rb"] - ["helper.rb"]).sort
9
+ t.verbose = true
10
+ #t.warning = true
11
+ end
12
+
13
+ task :default => [:test]
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,42 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = "fluent-plugin-in-udp-event"
6
+ gem.version = File.read("VERSION").strip
7
+ gem.authors = ["Alexander Blagoev"]
8
+ gem.email = ["alexander.i.blagoev@gmail.com"]
9
+ gem.summary = %q{Event driven udp input plugin for fluentd}
10
+ gem.description = gem.summary
11
+ gem.homepage = "https://github.com/ablagoev/fluent-plugin-in-udp-event"
12
+ gem.date = '2013-10-20'
13
+
14
+ gem.files = [
15
+ "lib/fluent/plugin/in_udp_event.rb",
16
+ "Gemfile",
17
+ "LICENSE.txt",
18
+ "README.rdoc",
19
+ "Rakefile",
20
+ "VERSION",
21
+ "fluent-plugin-in-udp-event.gemspec",
22
+ "test/helper.rb",
23
+ "test/fluent/plugin/test_in_udp_event.rb"
24
+ ]
25
+
26
+ gem.extra_rdoc_files = [
27
+ "LICENSE.txt",
28
+ "README.rdoc"
29
+ ]
30
+
31
+ gem.licenses = ["MIT"]
32
+
33
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
34
+
35
+ gem.require_paths = ["lib"]
36
+
37
+ gem.add_development_dependency "rake"
38
+
39
+ gem.add_runtime_dependency(%q<cool.io>, ["~> 1.1.1"])
40
+ gem.add_runtime_dependency "fluentd"
41
+ gem.add_runtime_dependency "json"
42
+ end
@@ -0,0 +1,124 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ #
4
+ # Fluent Input Plugin UDP Event
5
+ #
6
+ # Copyright (C) 2013 Alexander Blagoev
7
+
8
+ module Fluent
9
+ # Fluentd UDP input main class
10
+ class UdpEventInput < Input
11
+ MAX_BLOCKTIME = 2
12
+
13
+ Plugin.register_input('udp_event', self)
14
+
15
+ def initialize
16
+ super
17
+ require 'fluent/plugin/socket_util'
18
+ end
19
+
20
+ config_param :port, :integer, default: 242_24
21
+ config_param :bind, :string, default: '0.0.0.0'
22
+ config_param :max_message_size, :integer, default: 1024
23
+
24
+ def configure(conf)
25
+ super
26
+ end
27
+
28
+ def start
29
+ callback = method(:receive_data)
30
+
31
+ @loop = Coolio::Loop.new backend: :epoll
32
+
33
+ $log.debug "listening udp socket on #{@bind}:#{@port}"
34
+ @usock = SocketUtil.create_udp_socket(@bind)
35
+ @usock.bind(@bind, @port)
36
+
37
+ @handler = UdpHandler.new(@usock, @max_message_size, callback)
38
+ @loop.attach(@handler)
39
+
40
+ @thread = Thread.new(&method(:run))
41
+ end
42
+
43
+ def shutdown
44
+ # Force event every MAX_BLOCKTIME seconds to prevent 60 second timeout
45
+ # see ext/libev/ev.c MAX_BLOCKTIME
46
+ @watcher = Cool.io::TimerWatcher.new(MAX_BLOCKTIME, true)
47
+ @loop.attach(@watcher)
48
+
49
+ $log.debug 'stopping event loop'
50
+ begin
51
+ @loop.stop
52
+ rescue RuntimeError
53
+ end
54
+
55
+ $log.debug "closing udp socket on #{@bind}:#{@port}"
56
+ @handler.close
57
+
58
+ $log.debug 'closing watchers'
59
+ @loop.watchers.each { |w| w.detach }
60
+
61
+ $log.debug 'waiting for thread to finish'
62
+ @thread.join
63
+ $log.debug 'thread finished'
64
+ $log.debug 'terminating'
65
+ end
66
+
67
+ def run
68
+ @loop.run
69
+ rescue Exception => e
70
+ $log.error 'unexpected error', error: e.message
71
+ $log.error_backtrace
72
+ end
73
+
74
+ protected
75
+
76
+ def receive_data(data)
77
+ if data.bytesize == @max_message_size
78
+ $log.warn "message might be too big and truncated to #{@max_message_size}"
79
+ end
80
+
81
+ begin
82
+ parsed = JSON.parse(data)
83
+ rescue JSON::ParserError => e
84
+ $log.warn 'invalid json data', error: e.message
85
+ return
86
+ end
87
+
88
+ tag = parsed[0]
89
+ time = parsed[1].to_i
90
+ record = parsed[2]
91
+
92
+ if tag.nil? || time.nil? || record.nil?
93
+ $log.warn "invalid message supplied #{data}"
94
+ return
95
+ end
96
+
97
+ time ||= Engine.now
98
+
99
+ Engine.emit(tag, time, record)
100
+ rescue Exception => e
101
+ $log.warn data.dump, error: e.message
102
+ $log.debug_backtrace
103
+ end
104
+
105
+ private
106
+
107
+ # Class to handle the UDP layer
108
+ class UdpHandler < Coolio::IO
109
+ def initialize(io, max_message_size, callback)
110
+ super(io)
111
+ @io = io
112
+ @callback = callback
113
+ @max_message_size = max_message_size
114
+ end
115
+
116
+ def on_readable
117
+ msg, _ = @io.recvfrom_nonblock(@max_message_size)
118
+ @callback.call(msg)
119
+ rescue Exception => e
120
+ $log.error e.message, error: e.message
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,129 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'helper'
4
+
5
+ # Test case for the input plugin
6
+ class UdpEventInputTest < Test::Unit::TestCase
7
+ def setup
8
+ Fluent::Test.setup
9
+ require 'fluent/plugin/socket_util'
10
+ end
11
+
12
+ PORT = unused_port
13
+ CONFIG = %[
14
+ port #{PORT}
15
+ bind 127.0.0.1
16
+ ]
17
+
18
+ IPV6_CONFIG = %[
19
+ port #{PORT}
20
+ bind ::1
21
+ ]
22
+
23
+ def create_driver(conf = CONFIG)
24
+ Fluent::Test::InputTestDriver.new(Fluent::UdpEventInput).configure(conf)
25
+ end
26
+
27
+ def test_configure
28
+ configs = { '127.0.0.1' => CONFIG }
29
+ configs.merge!('::1' => IPV6_CONFIG) if ipv6_enabled?
30
+
31
+ configs.each_pair do |k, v|
32
+ d = create_driver(v)
33
+ assert_equal PORT, d.instance.port
34
+ assert_equal k, d.instance.bind
35
+ end
36
+ end
37
+
38
+ def test_receive_data
39
+ d = create_driver
40
+
41
+ tests = [
42
+ ['test.route', Time.now.to_i, { 'data' => 'test1' }],
43
+ ['test.route', Time.now.to_i, { 'data' => 'test2' }],
44
+ ['test.route', Time.now.to_i, { 'data' => 'test3' }]
45
+ ]
46
+
47
+ d.run do
48
+ @loop = d.instance.instance_variable_get(:@loop)
49
+
50
+ # Force event every 0.1 to prevent 60 second timeout
51
+ # see ext/libev/ev.c MAX_BLOCKTIME
52
+ @watcher = Cool.io::TimerWatcher.new(0.1, true)
53
+ @loop.attach(@watcher)
54
+
55
+ u = UDPSocket.new
56
+ u.connect('127.0.0.1', PORT)
57
+ tests.each do |message|
58
+ u.send(JSON.generate(message), 0)
59
+ end
60
+
61
+ sleep 0.2
62
+ end
63
+
64
+ assert_equal d.emits, tests
65
+ end
66
+
67
+ def test_invalid_message
68
+ d = create_driver
69
+
70
+ d.run do
71
+ @loop = d.instance.instance_variable_get(:@loop)
72
+
73
+ # Force event every 0.1 to prevent 60 second timeout
74
+ # see ext/libev/ev.c MAX_BLOCKTIME
75
+ @watcher = Cool.io::TimerWatcher.new(0.1, true)
76
+ @loop.attach(@watcher)
77
+
78
+ u = UDPSocket.new
79
+ u.connect('127.0.0.1', PORT)
80
+ u.send('invalid_json', 0)
81
+
82
+ sleep 0.2
83
+ end
84
+
85
+ assert_equal d.emits.length, 0
86
+ end
87
+
88
+ def test_invalid_structure
89
+ d = create_driver
90
+
91
+ d.run do
92
+ @loop = d.instance.instance_variable_get(:@loop)
93
+
94
+ # Force event every 0.1 to prevent 60 second timeout
95
+ # see ext/libev/ev.c MAX_BLOCKTIME
96
+ @watcher = Cool.io::TimerWatcher.new(0.1, true)
97
+ @loop.attach(@watcher)
98
+
99
+ u = UDPSocket.new
100
+ u.connect('127.0.0.1', PORT)
101
+ u.send(JSON.generate([]), 0)
102
+
103
+ sleep 0.2
104
+ end
105
+
106
+ assert_equal d.emits.length, 0
107
+ end
108
+
109
+ def test_enormous_message
110
+ d = create_driver
111
+
112
+ d.run do
113
+ @loop = d.instance.instance_variable_get(:@loop)
114
+
115
+ # Force event every 0.1s to prevent 60 second timeout
116
+ # see ext/libev/ev.c MAX_BLOCKTIME
117
+ @watcher = Cool.io::TimerWatcher.new(0.1, true)
118
+ @loop.attach(@watcher)
119
+
120
+ u = UDPSocket.new
121
+ u.connect('127.0.0.1', PORT)
122
+ u.send(JSON.generate(['test', Time.now.to_i, 'x' * 1500]), 0)
123
+
124
+ sleep 0.2
125
+ end
126
+
127
+ assert_equal d.emits.length, 0
128
+ end
129
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test/unit'
4
+ require 'fluent/test'
5
+ require 'fluent/plugin/in_udp_event'
6
+
7
+ unless defined?(Test::Unit::AssertionFailedError)
8
+ class Test::Unit::AssertionFailedError < StandardError
9
+ end
10
+ end
11
+
12
+ def unused_port
13
+ s = TCPServer.open(0)
14
+ port = s.addr[1]
15
+ s.close
16
+ port
17
+ end
18
+
19
+ def ipv6_enabled?
20
+ require 'socket'
21
+
22
+ begin
23
+ TCPServer.open('::1', 0)
24
+ true
25
+ rescue
26
+ false
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-in-udp-event
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Alexander Blagoev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: cool.io
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.1.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 1.1.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: fluentd
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: json
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Event driven udp input plugin for fluentd
70
+ email:
71
+ - alexander.i.blagoev@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files:
75
+ - LICENSE.txt
76
+ - README.rdoc
77
+ files:
78
+ - lib/fluent/plugin/in_udp_event.rb
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.rdoc
82
+ - Rakefile
83
+ - VERSION
84
+ - fluent-plugin-in-udp-event.gemspec
85
+ - test/helper.rb
86
+ - test/fluent/plugin/test_in_udp_event.rb
87
+ homepage: https://github.com/ablagoev/fluent-plugin-in-udp-event
88
+ licenses:
89
+ - MIT
90
+ metadata: {}
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ! '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 2.0.3
108
+ signing_key:
109
+ specification_version: 4
110
+ summary: Event driven udp input plugin for fluentd
111
+ test_files:
112
+ - test/helper.rb
113
+ - test/fluent/plugin/test_in_udp_event.rb