fluentd 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of fluentd might be problematic. Click here for more details.
- data/AUTHORS +1 -0
- data/COPYING +14 -0
- data/ChangeLog +178 -0
- data/README.rdoc +57 -0
- data/Rakefile +62 -0
- data/VERSION +1 -0
- data/bin/fluent-cat +6 -0
- data/bin/fluent-gem +10 -0
- data/bin/fluentd +6 -0
- data/fluent.conf +78 -0
- data/fluentd.gemspec +116 -0
- data/lib/fluent/buffer.rb +274 -0
- data/lib/fluent/command/cat.rb +299 -0
- data/lib/fluent/command/fluentd.rb +245 -0
- data/lib/fluent/config.rb +304 -0
- data/lib/fluent/engine.rb +224 -0
- data/lib/fluent/env.rb +6 -0
- data/lib/fluent/event.rb +159 -0
- data/lib/fluent/input.rb +41 -0
- data/lib/fluent/load.rb +23 -0
- data/lib/fluent/log.rb +277 -0
- data/lib/fluent/match.rb +189 -0
- data/lib/fluent/mixin.rb +170 -0
- data/lib/fluent/output.rb +466 -0
- data/lib/fluent/parser.rb +115 -0
- data/lib/fluent/plugin.rb +145 -0
- data/lib/fluent/plugin/buf_file.rb +181 -0
- data/lib/fluent/plugin/buf_memory.rb +97 -0
- data/lib/fluent/plugin/buf_zfile.rb +84 -0
- data/lib/fluent/plugin/in_http.rb +282 -0
- data/lib/fluent/plugin/in_stream.rb +187 -0
- data/lib/fluent/plugin/in_syslog.rb +174 -0
- data/lib/fluent/plugin/in_tail.rb +150 -0
- data/lib/fluent/plugin/out_copy.rb +72 -0
- data/lib/fluent/plugin/out_file.rb +111 -0
- data/lib/fluent/plugin/out_null.rb +44 -0
- data/lib/fluent/plugin/out_roundrobin.rb +72 -0
- data/lib/fluent/plugin/out_stdout.rb +34 -0
- data/lib/fluent/plugin/out_stream.rb +128 -0
- data/lib/fluent/plugin/out_test.rb +68 -0
- data/lib/fluent/test.rb +8 -0
- data/lib/fluent/test/base.rb +63 -0
- data/lib/fluent/test/input_test.rb +89 -0
- data/lib/fluent/test/output_test.rb +93 -0
- data/lib/fluent/version.rb +5 -0
- data/test/helper.rb +6 -0
- data/test/match.rb +115 -0
- data/test/plugin/in_http.rb +84 -0
- data/test/plugin/in_stream.rb +136 -0
- data/test/plugin/out_copy.rb +55 -0
- data/test/plugin/out_file.rb +82 -0
- data/test/plugin/out_roundrobin.rb +65 -0
- data/test/plugin/out_stream.rb +74 -0
- metadata +224 -0
@@ -0,0 +1,93 @@
|
|
1
|
+
#
|
2
|
+
# Fluent
|
3
|
+
#
|
4
|
+
# Copyright (C) 2011 FURUHASHI Sadayuki
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
module Fluent
|
19
|
+
module Test
|
20
|
+
|
21
|
+
|
22
|
+
class TestOutputChain
|
23
|
+
def initialize
|
24
|
+
@called = 0
|
25
|
+
end
|
26
|
+
|
27
|
+
def next
|
28
|
+
@called += 1
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :called
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
class OutputTestDriver < InputTestDriver
|
36
|
+
def initialize(klass, tag='test', &block)
|
37
|
+
super(klass, &block)
|
38
|
+
@tag = tag
|
39
|
+
end
|
40
|
+
|
41
|
+
attr_accessor :tag
|
42
|
+
|
43
|
+
def emit(record, time=Time.now)
|
44
|
+
es = OneEventStream.new(time.to_i, record)
|
45
|
+
chain = TestOutputChain.new
|
46
|
+
@instance.emit(@tag, es, chain)
|
47
|
+
assert_equal 1, chain.called
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
class BufferedOutputTestDriver < InputTestDriver
|
53
|
+
def initialize(klass, tag='test', &block)
|
54
|
+
super(klass, &block)
|
55
|
+
@entries = []
|
56
|
+
@expected_buffer = nil
|
57
|
+
@tag = tag
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_accessor :tag
|
61
|
+
|
62
|
+
def emit(record, time=Time.now)
|
63
|
+
@entries << [time.to_i, record]
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
def expect_format(str)
|
68
|
+
(@expected_buffer ||= '') << str
|
69
|
+
end
|
70
|
+
|
71
|
+
def run(&block)
|
72
|
+
result = nil
|
73
|
+
super {
|
74
|
+
es = ArrayEventStream.new(@entries)
|
75
|
+
buffer = @instance.format_stream(@tag, es)
|
76
|
+
|
77
|
+
block.call if block
|
78
|
+
|
79
|
+
if @expected_buffer
|
80
|
+
assert_equal(@expected_buffer, buffer)
|
81
|
+
end
|
82
|
+
|
83
|
+
chunk = MemoryBufferChunk.new('', buffer)
|
84
|
+
result = @instance.write(chunk)
|
85
|
+
}
|
86
|
+
result
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
data/test/helper.rb
ADDED
data/test/match.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
require 'fluent/match'
|
4
|
+
|
5
|
+
class MatchTest < Test::Unit::TestCase
|
6
|
+
include Fluent
|
7
|
+
|
8
|
+
def test_simple
|
9
|
+
assert_match('a', 'a')
|
10
|
+
assert_match('a.b', 'a.b')
|
11
|
+
assert_not_match('a', 'b')
|
12
|
+
assert_not_match('a.b', 'aab')
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_wildcard
|
16
|
+
assert_match('a*', 'a')
|
17
|
+
assert_match('a*', 'ab')
|
18
|
+
assert_match('a*', 'abc')
|
19
|
+
|
20
|
+
assert_match('*a', 'a')
|
21
|
+
assert_match('*a', 'ba')
|
22
|
+
assert_match('*a', 'cba')
|
23
|
+
|
24
|
+
assert_match('*a*', 'a')
|
25
|
+
assert_match('*a*', 'ba')
|
26
|
+
assert_match('*a*', 'ac')
|
27
|
+
assert_match('*a*', 'bac')
|
28
|
+
|
29
|
+
assert_not_match('a*', 'a.b')
|
30
|
+
assert_not_match('a*', 'ab.c')
|
31
|
+
assert_not_match('a*', 'ba')
|
32
|
+
assert_not_match('*a', 'ab')
|
33
|
+
|
34
|
+
assert_match('a.*', 'a.b')
|
35
|
+
assert_match('a.*', 'a.c')
|
36
|
+
assert_not_match('a.*', 'ab')
|
37
|
+
|
38
|
+
assert_match('a.*.c', 'a.b.c')
|
39
|
+
assert_match('a.*.c', 'a.c.c')
|
40
|
+
assert_not_match('a.*.c', 'a.c')
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_recursive_wildcard
|
44
|
+
assert_match('a.**', 'a')
|
45
|
+
assert_not_match('a.**', 'ab')
|
46
|
+
assert_not_match('a.**', 'abc')
|
47
|
+
assert_match('a.**', 'a.b')
|
48
|
+
assert_not_match('a.**', 'ab.c')
|
49
|
+
assert_not_match('a.**', 'ab.d.e')
|
50
|
+
|
51
|
+
assert_match('a**', 'a')
|
52
|
+
assert_match('a**', 'ab')
|
53
|
+
assert_match('a**', 'abc')
|
54
|
+
assert_match('a**', 'a.b')
|
55
|
+
assert_match('a**', 'ab.c')
|
56
|
+
assert_match('a**', 'ab.d.e')
|
57
|
+
|
58
|
+
assert_match('**.a', 'a')
|
59
|
+
assert_not_match('**.a', 'ba')
|
60
|
+
assert_not_match('**.a', 'c.ba')
|
61
|
+
assert_match('**.a', 'b.a')
|
62
|
+
assert_match('**.a', 'cb.a')
|
63
|
+
assert_match('**.a', 'd.e.a')
|
64
|
+
|
65
|
+
assert_match('**a', 'a')
|
66
|
+
assert_match('**a', 'ba')
|
67
|
+
assert_match('**a', 'c.ba')
|
68
|
+
assert_match('**a', 'b.a')
|
69
|
+
assert_match('**a', 'cb.a')
|
70
|
+
assert_match('**a', 'd.e.a')
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_or
|
74
|
+
assert_match('a.{b,c}', 'a.b')
|
75
|
+
assert_match('a.{b,c}', 'a.c')
|
76
|
+
assert_not_match('a.{b,c}', 'a.d')
|
77
|
+
|
78
|
+
assert_match('a.{b,c}.**', 'a.b')
|
79
|
+
assert_match('a.{b,c}.**', 'a.c')
|
80
|
+
assert_not_match('a.{b,c}.**', 'a.d')
|
81
|
+
assert_not_match('a.{b,c}.**', 'a.cd')
|
82
|
+
|
83
|
+
assert_match('a.{b.**,c}', 'a.b')
|
84
|
+
assert_match('a.{b.**,c}', 'a.b.c')
|
85
|
+
assert_match('a.{b.**,c}', 'a.c')
|
86
|
+
assert_not_match('a.{b.**,c}', 'a.c.d')
|
87
|
+
end
|
88
|
+
|
89
|
+
#def test_character_class
|
90
|
+
# assert_match('[a]', 'a')
|
91
|
+
# assert_match('[ab]', 'a')
|
92
|
+
# assert_match('[ab]', 'b')
|
93
|
+
# assert_not_match('[ab]', 'c')
|
94
|
+
#
|
95
|
+
# assert_match('[a-b]', 'a')
|
96
|
+
# assert_match('[a-b]', 'a')
|
97
|
+
# assert_match('[a-b]', 'b')
|
98
|
+
# assert_not_match('[a-b]', 'c')
|
99
|
+
#
|
100
|
+
# assert_match('[a-b0-9]', 'a')
|
101
|
+
# assert_match('[a-b0-9]', '0')
|
102
|
+
# assert_not_match('[a-b0-9]', 'c')
|
103
|
+
#end
|
104
|
+
|
105
|
+
def assert_match(pat, str)
|
106
|
+
m = GlobMatchPattern.new(pat)
|
107
|
+
assert_equal true, m.match(str)
|
108
|
+
end
|
109
|
+
|
110
|
+
def assert_not_match(pat, str)
|
111
|
+
m = GlobMatchPattern.new(pat)
|
112
|
+
assert_equal false, m.match(str)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'fluent/test'
|
2
|
+
require 'net/http'
|
3
|
+
|
4
|
+
class HttpInputTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
Fluent::Test.setup
|
7
|
+
end
|
8
|
+
|
9
|
+
CONFIG = %[
|
10
|
+
port 9911
|
11
|
+
bind 127.0.0.1
|
12
|
+
body_size_limit 10m
|
13
|
+
keepalive_timeout 5
|
14
|
+
]
|
15
|
+
|
16
|
+
def create_driver(conf=CONFIG)
|
17
|
+
Fluent::Test::InputTestDriver.new(Fluent::HttpInput).configure(conf)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_configure
|
21
|
+
d = create_driver
|
22
|
+
assert_equal 9911, d.instance.port
|
23
|
+
assert_equal '127.0.0.1', d.instance.bind
|
24
|
+
assert_equal 10*1024*1024, d.instance.body_size_limit
|
25
|
+
assert_equal 5, d.instance.keepalive_timeout
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_time
|
29
|
+
d = create_driver
|
30
|
+
|
31
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
32
|
+
Fluent::Engine.now = time
|
33
|
+
|
34
|
+
d.expect_emit "tag1", time, {"a"=>1}
|
35
|
+
d.expect_emit "tag2", time, {"a"=>2}
|
36
|
+
|
37
|
+
d.run do
|
38
|
+
d.expected_emits.each {|tag,time,record|
|
39
|
+
res = post("/#{tag}", {"json"=>record.to_json})
|
40
|
+
assert_equal "200", res.code
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_json
|
46
|
+
d = create_driver
|
47
|
+
|
48
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
49
|
+
|
50
|
+
d.expect_emit "tag1", time, {"a"=>1}
|
51
|
+
d.expect_emit "tag2", time, {"a"=>2}
|
52
|
+
|
53
|
+
d.run do
|
54
|
+
d.expected_emits.each {|tag,time,record|
|
55
|
+
res = post("/#{tag}", {"json"=>record.to_json, "time"=>time.to_s})
|
56
|
+
assert_equal "200", res.code
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_msgpack
|
62
|
+
d = create_driver
|
63
|
+
|
64
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
65
|
+
|
66
|
+
d.expect_emit "tag1", time, {"a"=>1}
|
67
|
+
d.expect_emit "tag2", time, {"a"=>2}
|
68
|
+
|
69
|
+
d.run do
|
70
|
+
d.expected_emits.each {|tag,time,record|
|
71
|
+
res = post("/#{tag}", {"msgpack"=>record.to_msgpack, "time"=>time.to_s})
|
72
|
+
assert_equal "200", res.code
|
73
|
+
}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def post(path, params)
|
78
|
+
http = Net::HTTP.new("127.0.0.1", 9911)
|
79
|
+
req = Net::HTTP::Post.new(path, {})
|
80
|
+
req.set_form_data(params)
|
81
|
+
http.request(req)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'fluent/test'
|
2
|
+
|
3
|
+
module StreamInputTest
|
4
|
+
def setup
|
5
|
+
Fluent::Test.setup
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_time
|
9
|
+
d = create_driver
|
10
|
+
|
11
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
12
|
+
Fluent::Engine.now = time
|
13
|
+
|
14
|
+
d.expect_emit "tag1", time, {"a"=>1}
|
15
|
+
d.expect_emit "tag2", time, {"a"=>2}
|
16
|
+
|
17
|
+
d.run do
|
18
|
+
d.expected_emits.each {|tag,time,record|
|
19
|
+
send_data [tag, 0, record].to_msgpack
|
20
|
+
}
|
21
|
+
sleep 0.5
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_message
|
26
|
+
d = create_driver
|
27
|
+
|
28
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
29
|
+
|
30
|
+
d.expect_emit "tag1", time, {"a"=>1}
|
31
|
+
d.expect_emit "tag2", time, {"a"=>2}
|
32
|
+
|
33
|
+
d.run do
|
34
|
+
d.expected_emits.each {|tag,time,record|
|
35
|
+
send_data [tag, time, record].to_msgpack
|
36
|
+
}
|
37
|
+
sleep 0.5
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_forward
|
42
|
+
d = create_driver
|
43
|
+
|
44
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
45
|
+
|
46
|
+
d.expect_emit "tag1", time, {"a"=>1}
|
47
|
+
d.expect_emit "tag1", time, {"a"=>2}
|
48
|
+
|
49
|
+
d.run do
|
50
|
+
entries = []
|
51
|
+
d.expected_emits.each {|tag,time,record|
|
52
|
+
entries << [time, record]
|
53
|
+
}
|
54
|
+
send_data ["tag1", entries].to_msgpack
|
55
|
+
sleep 0.5
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_packed_forward
|
60
|
+
d = create_driver
|
61
|
+
|
62
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
63
|
+
|
64
|
+
d.expect_emit "tag1", time, {"a"=>1}
|
65
|
+
d.expect_emit "tag1", time, {"a"=>2}
|
66
|
+
|
67
|
+
d.run do
|
68
|
+
entries = ''
|
69
|
+
d.expected_emits.each {|tag,time,record|
|
70
|
+
[time, record].to_msgpack(entries)
|
71
|
+
}
|
72
|
+
send_data ["tag1", entries].to_msgpack
|
73
|
+
sleep 0.5
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def create_driver(klass, conf)
|
78
|
+
Fluent::Test::InputTestDriver.new(klass).configure(conf)
|
79
|
+
end
|
80
|
+
|
81
|
+
def send_data(data)
|
82
|
+
io = connect
|
83
|
+
begin
|
84
|
+
io.write data
|
85
|
+
ensure
|
86
|
+
io.close
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class TcpInputTest < Test::Unit::TestCase
|
92
|
+
include StreamInputTest
|
93
|
+
|
94
|
+
CONFIG = %[
|
95
|
+
port 13998
|
96
|
+
bind 127.0.0.1
|
97
|
+
]
|
98
|
+
|
99
|
+
def create_driver(conf=CONFIG)
|
100
|
+
super(Fluent::TcpInput, conf)
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_configure
|
104
|
+
d = create_driver
|
105
|
+
assert_equal 13998, d.instance.port
|
106
|
+
assert_equal '127.0.0.1', d.instance.bind
|
107
|
+
end
|
108
|
+
|
109
|
+
def connect
|
110
|
+
TCPSocket.new('127.0.0.1', 13998)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class UnixInputTest < Test::Unit::TestCase
|
115
|
+
include StreamInputTest
|
116
|
+
|
117
|
+
TMP_DIR = File.dirname(__FILE__) + "/../tmp"
|
118
|
+
|
119
|
+
CONFIG = %[
|
120
|
+
path #{TMP_DIR}/unix
|
121
|
+
]
|
122
|
+
|
123
|
+
def create_driver(conf=CONFIG)
|
124
|
+
super(Fluent::UnixInput, conf)
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_configure
|
128
|
+
d = create_driver
|
129
|
+
assert_equal "#{TMP_DIR}/unix", d.instance.path
|
130
|
+
end
|
131
|
+
|
132
|
+
def connect
|
133
|
+
UNIXSocket.new("#{TMP_DIR}/unix")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'fluent/test'
|
2
|
+
|
3
|
+
class CopyOutputTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
Fluent::Test.setup
|
6
|
+
end
|
7
|
+
|
8
|
+
CONFIG = %[
|
9
|
+
<store>
|
10
|
+
type test
|
11
|
+
name c0
|
12
|
+
</store>
|
13
|
+
<store>
|
14
|
+
type test
|
15
|
+
name c1
|
16
|
+
</store>
|
17
|
+
<store>
|
18
|
+
type test
|
19
|
+
name c2
|
20
|
+
</store>
|
21
|
+
]
|
22
|
+
|
23
|
+
def create_driver(conf = CONFIG)
|
24
|
+
Fluent::Test::OutputTestDriver.new(Fluent::CopyOutput).configure(conf)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_configure
|
28
|
+
d = create_driver
|
29
|
+
|
30
|
+
outputs = d.instance.outputs
|
31
|
+
assert_equal 3, outputs.size
|
32
|
+
assert_equal Fluent::TestOutput, outputs[0].class
|
33
|
+
assert_equal Fluent::TestOutput, outputs[1].class
|
34
|
+
assert_equal Fluent::TestOutput, outputs[2].class
|
35
|
+
assert_equal "c0", outputs[0].name
|
36
|
+
assert_equal "c1", outputs[1].name
|
37
|
+
assert_equal "c2", outputs[2].name
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_emit
|
41
|
+
d = create_driver
|
42
|
+
|
43
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
44
|
+
d.emit({"a"=>1}, time)
|
45
|
+
d.emit({"a"=>2}, time)
|
46
|
+
|
47
|
+
d.instance.outputs.each {|o|
|
48
|
+
assert_equal [
|
49
|
+
[time, {"a"=>1}],
|
50
|
+
[time, {"a"=>2}],
|
51
|
+
], o.events
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|